2010-10-16 211 views
31

Cómo hacer la actualización inmediatamente cuando se cambió el valor de jSpinner.JSpinner Cambio de valor Eventos

ChangeListener listener = new ChangeListener() { 
    public void stateChanged(ChangeEvent e) { 
    jLabel.setText(e.getSource()); 
    } 
}; 

spinner1.addChangeListener(listener); 

El código anterior no cambia el texto de la etiqueta de forma automática, es necesario que haga clic de nuevo en cualquier lugar de actualizar.

+1

La próxima vez por favor una SSCCE (http://sscce.org) por lo podemos ver el contexto de cómo está usando el código. – camickr

+0

Mismo problema, todavía no he visto una solución. El método ChangeListener no se llama hasta que se pierde el foco de JSpinner. He hecho una solución con keylisteners, pero eso es feo – spuas

Respuesta

7

El código que muestra parece correcto. Como referencia, aquí hay un ejemplo de trabajo.

Adición: Mientras que el JSpinner tiene el foco, las teclas de flecha izquierda y derecha mueven el cursor. La flecha hacia arriba se incrementa y la flecha hacia abajo disminuye el campo que contiene el cursor. El cambio es (efectivamente) simultáneo tanto en la ruleta como en la etiqueta. Para acceder al JFormattedTextField del JSpinner.DateEditor, use el método del padre getTextField(). Luego, se puede usar un oyente de intercalación apropiado o un oyente de entrada de texto para actualizar la etiqueta como se desee.

Adición: Actualice para usar setCommitsOnValidEdit, como se sugiere here.

import java.awt.EventQueue; 
import java.awt.GridLayout; 
import java.util.Calendar; 
import java.util.Date; 
import javax.swing.JFormattedTextField; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JSpinner; 
import javax.swing.JSpinner.DateEditor; 
import javax.swing.SpinnerDateModel; 
import javax.swing.event.ChangeEvent; 
import javax.swing.event.ChangeListener; 
import javax.swing.text.DefaultFormatter; 

/** 
* @see https://stackoverflow.com/questions/2010819 
* @see https://stackoverflow.com/questions/3949518 
*/ 
public class JSpinnerTest extends JPanel { 

    public static void main(String args[]) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       JFrame f = new JFrame("JSpinnerTest"); 
       f.add(new JSpinnerTest()); 
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       f.pack(); 
       f.setVisible(true); 
      } 
     }); 
    } 

    public JSpinnerTest() { 
     super(new GridLayout(0, 1)); 
     final JLabel label = new JLabel(); 
     final JSpinner spinner = new JSpinner(); 
     Calendar calendar = Calendar.getInstance(); 
     Date initDate = calendar.getTime(); 
     calendar.add(Calendar.YEAR, -5); 
     Date earliestDate = calendar.getTime(); 
     calendar.add(Calendar.YEAR, 10); 
     Date latestDate = calendar.getTime(); 
     spinner.setModel(new SpinnerDateModel(
      initDate, earliestDate, latestDate, Calendar.MONTH)); 
     DateEditor editor = new JSpinner.DateEditor(spinner, "MMM yyyy"); 
     spinner.setEditor(editor); 
     JFormattedTextField jtf = editor.getTextField(); 
     DefaultFormatter formatter = (DefaultFormatter) jtf.getFormatter(); 
     formatter.setCommitsOnValidEdit(true); 
     spinner.addChangeListener(new ChangeListener() { 

      @Override 
      public void stateChanged(ChangeEvent e) { 
       JSpinner s = (JSpinner) e.getSource(); 
       label.setText(s.getValue().toString()); 
      } 
     }); 
     label.setText(initDate.toString()); 
     this.add(spinner); 
     this.add(label); 
    } 
} 
+0

Esto es correcto pero no resuelve el problema mencionado anteriormente: al editar manualmente, stateChanged solo se invoca después de que el JSpinner pierda el foco o si el usuario presiona la tecla Enter pero no con cada clave mecanografiada – spuas

+0

Todavía no hay solución en su respuesta. –

+0

@Andrei Vajna II: Gracias por explicar su voto a favor, pero voy a remitirme al usuario236501. He verificado el ejemplo y lo actualicé para eliminar una importación espuria. – trashgod

2

problema aquí es que cuando se modifica el valor JSpinner manualmente escribiendo en el teclado, el evento stateChanged no se dispara hasta que el enfoque se pierde por la JSpinner o hasta que la tecla Enter se ha pulsado.

Si desea cargar el valor, se necesita un KeyListener que realizará un setValue en el JSpinner para cada clave escrita.

dejo un ejemplo aquí por un JSpinner con un SpinnerNumberModel:

JSpinner spinner= new JSpinner(); 
spinner.setModel(new SpinnerNumberModel(0, 0, Integer.MAX_VALUE, 1)); 
spinner.addChangeListener(new ChangeListener() { 
    @Override 
    public void stateChanged(ChangeEvent e) { 
     jLabel.setText(spinner.getValue()); 
    } 
}); 
final JTextField jtf = ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField(); 
jtf.addKeyListener(new KeyAdapter() { 
    @Override 
    public void keyReleased(KeyEvent e) { 
     String text = jtf.getText().replace(",", ""); 
     int oldCaretPos = jtf.getCaretPosition(); 
     try { 
      Integer newValue = Integer.valueOf(text); 
      spinner.setValue(newValue); 
      jtf.setCaretPosition(oldCaretPos); 
     } catch(NumberFormatException ex) { 
      //Not a number in text field -> do nothing 
     } 
    } 
}); 
+1

hey, es la primera vez hoy (que está en su final, en lo que respecta al trabajo): no use keylisteners: no son lo suficientemente buenos, porque omiten el texto pegado en el campo – kleopatra

43

La respuesta es configurar el formateador utilizado en la JFormattedTextField que es un hijo del editor de la ruleta:

formatter.setCommitsOnValidEdit(true); 

Desafortunadamente, meter la mano en eso es tan largo y sucio como la frase introductoria:

final JSpinner spinner = new JSpinner(); 
    JComponent comp = spinner.getEditor(); 
    JFormattedTextField field = (JFormattedTextField) comp.getComponent(0); 
    DefaultFormatter formatter = (DefaultFormatter) field.getFormatter(); 
    formatter.setCommitsOnValidEdit(true); 
    spinner.addChangeListener(new ChangeListener() { 

     @Override 
     public void stateChanged(ChangeEvent e) { 
      LOG.info("value changed: " + spinner.getValue()); 
     } 
    }); 

un poco (pero no mucho) más limpia forma podría ser la subclase NumberEditor y exponer un método que permite la configuración

+1

En lugar de utilizar detalles de getComponent, Oracle exmaples usa esta secuencia para recuperar el JFormattedTextField: 'public JFormattedTextField getTextField (JSpinner spinner) {return ((JSpinner.DefaultEditor) spinner.getEditor()). GetTextField(); } 'He eliminado la comprobación de errores, pero esa es otra posibilidad. –

0

Soy nuevo por lo que podría estar infringiendo algunas reglas y podría llegar tarde. Pero encontré algunas de las respuestas un poco confusas, así que jugué en NetBeans IDE y descubrí que si hace clic derecho en el componente jspinner GUI colocado en su jform y va a eventos-> cambiar, se generará código para usted.

1

Puede ser una respuesta tardía, pero puede usar mi enfoque.
Como spuas mencionado anteriormente, el problema es que el evento stateChanged se activa solo cuando se pierde el foco o se presiona la tecla Entrar.
El uso de KeyListeners tampoco es una buena idea.
En su lugar, sería mejor usar DocumentListener.He modificado el ejemplo de spuas un poco y eso es lo que tengo:

JSpinner spinner= new JSpinner(); 
spinner.setModel(new SpinnerNumberModel(0, 0, Integer.MAX_VALUE, 1)); 
final JTextField jtf = ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField(); 
     jtf.getDocument().addDocumentListener(new DocumentListener() {    

     private volatile int value = 0; 

     @Override 
     public void removeUpdate(DocumentEvent e) { 
      showChangedValue(e);  
     } 

     @Override 
     public void insertUpdate(DocumentEvent e) { 
      showChangedValue(e);     
     } 

     @Override 
     public void changedUpdate(DocumentEvent e) { 
      showChangedValue(e);  
     } 

     private void showChangedValue(DocumentEvent e){ 
      try { 
       String text = e.getDocument().getText(0, e.getDocument().getLength()); 
       if (text==null || text.isEmpty()) return; 
        int val = Integer.parseInt(text).getValue(); 
       if (value!=val){ 
        System.out.println(String.format("changed value: %d",val));    
        value = val; 
       }  
      } catch (BadLocationException | NumberFormatException e1) { 
          //handle if you want 
      }   
     } 
}); 
0

La última respuesta se puede variar un poco para que sea un poco más flexible. Simplemente puede usar este nuevo MyJSpinner en lugar de cualquier JSpinner. El cambio más importante es que se puede utilizar esta nueva versión con cualquier modelo subyacente de la JSpinner (int, double, byte, etc.)

public class MyJSpinner extends JSpinner{ 
     boolean setvalueinprogress=false; 
     public MyJSpinner() 
     { 
      super(); 
      final JTextField jtf = ((JSpinner.DefaultEditor) getEditor()).getTextField(); 
      jtf.getDocument().addDocumentListener(new DocumentListener() {    

        @Override 
        public void removeUpdate(DocumentEvent e) { 
         showChangedValue(e);  
        } 

        @Override 
        public void insertUpdate(DocumentEvent e) { 
         showChangedValue(e);     
        } 

        @Override 
        public void changedUpdate(DocumentEvent e) { 
         showChangedValue(e);  
        } 

        private void showChangedValue(DocumentEvent e){ 
         try { 
          if (!setvalueinprogress) 
           MyJSpinner.this.commitEdit();  
         } catch (NumberFormatException | ParseException ex) { 
             //handle if you want 
          Exceptions.printStackTrace(ex); 
         }  
        } 
      }); 
     } 

    @Override 
    public void setValue(Object value) { 
     setvalueinprogress=true; 
     super.setValue(value); 
     setvalueinprogress=false; 
    } 

} 
Cuestiones relacionadas