2011-08-29 3 views
7

Je suis en train de créer un éditeur de niveau pour mon jeu. J'ai un panneau de propriétés où je peux modifier les propriétés de l'objet sélectionné. J'ai aussi un bouton Enregistrer pour écrire le niveau xml.Java Swing: Focus question

Un champ édition est soumis (*) lorsque le composant éditeur a perdu le focus ou Entrez est pressé. Cela fonctionne très bien, mais le seul problème est que lorsque j'ai cette séquence d'actions:

  1. Modifier un champ
  2. Appuyez sur le bouton Enregistrer

Parce que, ce qui se passe est la suivante:

  1. Je modifier le champ
  2. j'appuie sur le bouton enregistrer
  3. le chier vel est enregistré
  4. Le champ a perdu le focus
  5. La modification est soumise

Comme vous pouvez le voir, c'est le mauvais ordre. Bien sûr, je veux que le champ à perdre son attention, ce qui provoque le soumettre et puis enregistrer le niveau.

Existe-t-il une astuce, un hack ou une solution de contournement pour que le champ ne perde pas le focus, puis exécute l'action listener du bouton de sauvegarde?

Merci d'avance.

(* submit = la modification du champ est également dans la propriété de l'objet)


EDIT: Pour le terrain, je suis sur un FocusAdapter avec focusLost:

FocusAdapter focusAdapter = new FocusAdapter() 
{ 

    @Override 
    public void focusLost(FocusEvent e) 
    { 
     compProperties.setProperty(i, getColor()); 
     record(); // For undo-redo mechanism 
    } 
}; 

Et pour le bouton un simple ActionListener avec actionPerformed`.

btnSave.addActionListener(new java.awt.event.ActionListener() { 
    public void actionPerformed(java.awt.event.ActionEvent evt) { 
     // Save the level 
    } 
}); 
+1

Aucune idée du fonctionnement du code, merci de poster ici le code approprié, car il existe d'autres options en utilisant 'DocumentListener', ou en utilisant' AncesorListener', ou juste en tapant 'FocucHell' dans' invokeLater' avec 'myTextField.setText (myTextField.getText); ' – mKorbel

+0

@mKorbel: J'ai essayé d'encapsuler le processus de sauvegarde dans un' invokeLater', mais il est toujours dans le mauvais ordre. –

+1

Voir aussi cette [Q & A] (http://stackoverflow.com/questions/6803976/focusevent-doesnt-get-the-last-value-of-jformattedtextfield-how-i-can-get-it/6804749#6804749) . – trashgod

Répondre

3

Hmm ... ne peut pas reproduire: dans l'extrait ci-dessous la perte est toujours informé avant l'actionPerfomed, indépendant si je clique sur le bouton ou utiliser le mnémonique:

final JTextField field = new JTextField("some text to change"); 
    FocusAdapter focus = new FocusAdapter() { 

     @Override 
     public void focusLost(FocusEvent e) { 
      LOG.info("lost: " + field.getText()); 
     } 

    }; 
    field.addFocusListener(focus); 

    Action save = new AbstractAction("save") { 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      LOG.info("save: " + field.getText()); 
     } 
    }; 
    save.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_S); 
    JButton button = new JButton(save); 
    JComponent box = Box.createHorizontalBox(); 
    box.add(field); 
    box.add(button); 

Sur la D'autre part, l'accent est une propriété délicate sur laquelle s'appuyer, la commande pourrait dépendre du système (le mien est win vista). Vérifiez comment l'extrait se comporte sur le vôtre.

  • Si vous voyez la même séquence que je fais, le problème est ailleurs
  • si vous obtenez la sauvegarde avant la perte, essayez d'envelopper le l'action enregistrer dans invokeLater (qu'elle met à la fin du EventQueue, il est donc exécuté après tous les événements en attente)

    Action save = new AbstractAction("save") { 
    
        @Override 
        public void actionPerformed(ActionEvent e) { 
         SwingUtilities.invokeLater(new Runnable() { 
          public void run() { 
           LOG.info("save: " + field.getText()); 
          } 
         }); 
        } 
    }; 
    
+0

' le problème est ailleurs 'par OP J'ai ajouté des flux d'E/S 1) enlever Focus & ActionListener dans javax.swing.Action 2) rediriger les flux d'E/S vers le thread Runnable #, 3) tout est fait puis rajouter Focus & ActionListener, 4) de la même façon que ça marche si j'ai retardé ça en deux étapes chacune en deux invokeLater(), 5) Dealyed Events de ActionListener en utilisant javax.swi ng.Timer & javax.swing.Action, 6) ressemble à Action est un peu diferrent comme ActionListener 7) tout à propos de déplacer Focus de JButton à JTexfield ont été enveloppés dans invokeLater() +1 – mKorbel

0

Normalement, l'emballage de votre enregistrer le code dans un SwingUtilities.invokeLater() devrait faire l'affaire. Comme vous l'avez déjà mentionné, cela ne fonctionne pas? Essayez ceci:

private boolean editFocus = false; 
FocusAdapter focusAdapter = new FocusAdapter() 
{ 
    @Override 
    public void focusGained(FocusEvent e){ 
     editFocus = true; 
    } 
    @Override 
    public void focusLost(FocusEvent e){ 
     compProperties.setProperty(i, getColor()); 
     record(); // For undo-redo mechanism 
     editFocus = false; 
     if (saveRequested){ 
      save();    
     } 
    } 
}; 

et pour votre bouton:

private boolean saveRequested = false; 

btnSave.addActionListener(new java.awt.event.ActionListener() { 
    public void actionPerformed(java.awt.event.ActionEvent evt) { 
     if (editFocus){ 
      saveRequested = true; 
      return; 
     } else { 
      save(); 
     } 
    } 
}); 

et votre méthode save:

private void save(){ 
    // do your saving work 
    saveRequested = false; 
} 

Cela ne fonctionne que lorsque votre FocusLost est appelée après l'action de votre bouton. Si soudainement la commande est correcte, ce code recevra deux fois save(). Mais encore une fois, envelopper votre code save() dans votre approche originale devrait fonctionner, car le code de sauvegarde sera exécuté après le traitement de tous les événements. C'est après avoir traité votre clic de bouton et vos événements focusLost. Parce que votre code focusLost s'exécute immédiatement (il n'est pas enveloppé dans invokeLater()), le code focusLost doit toujours être exécuté avant votre code de sauvegarde. Cela ne signifie pas que l'ordre des événements sera correct! Mais le code associé aux événements sera exécuté dans le bon ordre.