2010-10-16 15 views
31

Come eseguire immediatamente l'aggiornamento quando il valore di jSpinner è stato modificato.JSpinner Variazione di valore Eventi

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

spinner1.addChangeListener(listener); 

Il codice sopra non modifica automaticamente il testo dell'etichetta, ha richiesto di fare nuovamente clic su qualsiasi punto per aggiornare.

+1

La prossima volta si prega di inviare una SSCCE (http://sscce.org) così possiamo vedere il contesto di come stai usando il codice. – camickr

+0

Lo stesso problema, non ho ancora visto una soluzione. Il metodo ChangeListener non viene chiamato fino a quando lo stato attivo non viene perso da JSpinner. Ho risolto il problema con keylisteners, ma questo è brutto – spuas

risposta

7

Il codice visualizzato è corretto. Per riferimento, ecco un esempio funzionante.

Addendum: Mentre lo JSpinner è attivo, i tasti freccia sinistra e destra spostano il cursore. La freccia su aumenta e la freccia giù diminuisce il campo contenente il cursore. Il cambiamento è (efficace) simultaneo sia nello spinner che nell'etichetta.

Per accedere allo JFormattedTextField dello JSpinner.DateEditor, utilizzare il metodo getTextField() del genitore. Un ascoltatore di caret adatto o un listener di input di testo può quindi essere utilizzato per aggiornare l'etichetta come desiderato.

Addendum: aggiornamento per utilizzare setCommitsOnValidEdit, come suggerito 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

Questo è corretto ma non risolve il problema sopra indicato: quando si modifica manualmente, stateChanged viene chiamato solo dopo il focus perdite di JSpinner o se l'utente preme il tasto Invio ma non con ciascuno tasto digitato – spuas

+0

Non c'è ancora una soluzione nella risposta. –

+0

@Andrei Vajna II: Grazie per aver spiegato il tuo voto negativo, ma rimanderò a user236501. Ho verificato l'esempio e l'ho aggiornato per rimuovere un'importazione spuria. – trashgod

2

problema qui è che quando si modifica manualmente il valore JSpinner digitando sulla tastiera, l'evento stateChanged non viene generato fino a quando la messa a fuoco viene perso dal JSpinner o fino a quando il tasto Invio è stato premuto.

Se si desidera caricare il valore, è necessario un KeyListener che eseguirà un valore setValue nello JSpinner per ogni tasto digitato.

lascio un esempio qui per 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

ehi, è la prima volta oggi (che è alla fine, per quanto riguarda il lavoro): non usare keylisteners - non sono abbastanza buoni, perché mancano il testo incollato nel campo – kleopatra

43

La risposta è quello di configurare il formattatore utilizzato nella JFormattedTextField che è un figlio del direttore della trottola:

formatter.setCommitsOnValidEdit(true); 

Purtroppo, avere la mano su di esso è lunga e sporca come la frase introduttiva:

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 po '(ma non di molto) più pulita modo potrebbe essere quello di creare una sottoclasse NumberEditor ed esporre un metodo che consente la configurazione

+1

Piuttosto che usare i dettagli di getComponent, il Oracle exmaples usa questa sequenza per recuperare JFormattedTextField: 'public JFormattedTextField getTextField (JSpinner spinner) {return ((JSpinner.DefaultEditor) spinner.getEditor()). GetTextField(); } 'Ho rimosso il controllo degli errori, ma questa è un'altra possibilità. –

0

io sono nuovo quindi potrei essere rompendo alcune regole e potrei essere in ritardo. Ma ho trovato alcune risposte un po 'confuse, quindi ho giocato con l'IDE di NetBeans e ho scoperto che se si fa clic con il pulsante destro del mouse sulla componente jspinner della GUI posizionata su jform e si passa ad eventi-> cambia, il codice verrà generato automaticamente.

1

Potrebbe essere una risposta tardiva, ma è possibile utilizzare il mio approccio.
Come spuas menzionato sopra il problema è che l'evento stateChanged viene generato solo quando si interrompe la messa a fuoco o si preme il tasto Invio.
L'utilizzo di KeyListeners non è una buona idea.
È preferibile utilizzare DocumentListener.Ho modificato l'esempio di spuas un po 'e questo è quello che ho ottenuto:

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

L'ultima risposta può essere riordinato un po' per renderlo un po 'più flessibile. Puoi semplicemente usare questo nuovo MyJSpinner al posto di qualsiasi JSpinner. Il cambiamento più grande è che è possibile utilizzare questa nuova versione con qualsiasi modello di fondo della JSpinner (int, double, byte, ecc)

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

} 
Problemi correlati