2011-08-29 15 views
7

Estoy haciendo un editor de niveles para mi juego. Tengo un panel de propiedades donde puedo modificar las propiedades del objeto seleccionado. También tengo un botón Guardar para escribir el nivel xml.Java Swing: Problema de enfoque

se presenta un campo de edición (*) cuando el componente de edición pierde el foco o Introduzca se presiona. Esto es trabajo grande, pero el único problema es que cuando tengo esta secuencia de acciones:

  1. Editar un campo
  2. Pulse el botón de guardar

Porque, lo que sucede es lo siguiente:

  1. edito el campo
  2. pulsar el botón de guardar
  3. el le vel se guarda
  4. El campo pierde el foco
  5. La edición se presenta

Como se puede ver, este es el orden equivocado. Por supuesto, quiero que el campo pierda su foco, lo que causa el envío y luego guarda el nivel.

¿Existe algún truco, truco o solución para hacer que el campo primero pierda el foco y luego realice el detector de acciones del botón de guardar?

Gracias de antemano.

(* submit = la edición en el campo también se hace en la propiedad del objeto)


EDITAR: Para el campo estoy usando un FocusAdapter con focusLost:

FocusAdapter focusAdapter = new FocusAdapter() 
{ 

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

Y para el botón un simple ActionListener con actionPerformed`.

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

no importa cómo funciona el código, por favor, publique aquí el código relevante, porque hay otras opciones usando 'DocumentListener', o usando' AncesorListener', o simplemente enviándole 'FocucHell' en' invokeLater' con 'myTextField.setText (myTextField.getText); ' – mKorbel

+0

@mKorbel: Intenté encapsular el proceso de guardado en un' invokeLater', pero todavía está en el orden incorrecto. –

+1

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

Respuesta

3

Hmm ... no se puede reproducir: en el siguiente fragmento de código a los perdidos siempre se notifica antes de la actionPerfomed, independientemente de si hago clic en el botón o utilizar la tecla de acceso:

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); 

Por Por otro lado, el enfoque es una propiedad difícil de confiar, el orden puede ser dependiente del sistema (el mío es win vista). Comprueba cómo se comporta el fragmento en el tuyo.

  • Si ves la misma secuencia que yo, el problema está en otra parte
  • si se obtiene el salve antes de la perdida, tratar de envolver el de la acción de guardar en invokeLater (lo que lo coloca en el extremo del EventQueue, por lo que se ejecuta después de que todos los eventos pendientes)

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

' el problema está en otro lugar' por OP agregué flujos de E/S 1) eliminando Focus & ActionListener dentro de javax.swing.Action 2) redirigiendo flujos de E/S a la secuencia Runnable #, 3) todo listo, luego agrega Focus & ActionListener, 4) de la misma manera que funciona si retrasé eso en dos pasos, cada uno en dos invokeLater(), 5) traté Eventos de ActionListener usando javax.swi ng.Timer & javax.swing.Action, 6) parece que Action es un poco diferente como ActionListener 7) todo sobre move Focus de JButton a JTexfield fue envuelto en invokeLater() +1 – mKorbel

0

Normalmente, envolviendo su reserva código en un SwingUtilities.invokeLater() debe hacer el truco. Como ya lo mencionaste, esto no funciona? Prueba esto:

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();    
     } 
    } 
}; 

y para su botón:

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(); 
     } 
    } 
}); 

y luego guardar su método:

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

Esto sólo funciona cuando su focusLost se llama a la acción después de su botón. Si de repente el pedido es correcto, este código recibirá save() llamado dos veces.

Pero una vez más, debe funcionar su código save() en su enfoque original, ya que el código de guardado se ejecutará después de procesar todos los eventos. Eso es después de procesar el clic de tu botón y tus eventos FocusLost. Debido a que su código de FocusLost se ejecuta inmediatamente (no está incluido en un invokeLater()), el código de focusLost se debe ejecutar siempre antes de su código de guardado. ¡Esto no significa que el orden del evento será correcto! Pero el código asociado a los eventos se ejecutará en el orden correcto.