JSpinner Events de changement de valeur

Comment faire la mise à jour immédiatement lorsque la valeur jSpinner a été changée.

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

spinner1.addChangeListener(listener);

le code ci-dessus ne modifie pas le texte de l'étiquette automatiquement, il vous a demandé de cliquer de nouveau n'importe où pour mettre à jour.

33
demandé sur mKorbel 2010-10-16 18:56:17

6 réponses

la réponse est de configurer le formatter utilisé dans le JFormattedTextField qui est un enfant de l'éditeur du spinner:

    formatter.setCommitsOnValidEdit(true);

malheureusement, mettre la main dessus est aussi long et sale que la phrase d'introduction:

    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 moyen légèrement (mais pas beaucoup) plus propre pourrait être de sous-classe Numéroeditor et exposer une méthode qui permet la config

45
répondu kleopatra 2011-09-28 17:37:24

le code que vous affichez semble correct. Pour référence, voici un exemple de travail.

Addendum: alors que le JSpinner a la mise au point, les flèches gauche et droite déplacent le caret. La flèche vers le haut incréments et la flèche vers le bas décrémente le champ contenant le curseur. Le changement est (effectivement) simultané dans le spinner et le label.

pour accéder au JFormattedTextField du JSpinner.DateEditor , utilisez les getTextField() méthode. Approprié signe auditeur ou de saisie de texte auditeur peut alors être utilisé pour mettre à jour l'étiquette souhaitée.

Addendum: mise à Jour pour utiliser setCommitsOnValidEdit , comme l'a suggéré ici .

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);
    }
}
8
répondu trashgod 2017-05-23 12:09:26

le problème ici est que lorsque vous éditez la valeur JSpinner manuellement en tapant à partir du clavier, l'événement stateChanged n'est pas déclenché tant que le focus n'est pas perdu par le JSpinner ou tant que la touche Entrée n'a pas été pressée.

si vous voulez télécharger la valeur, un KeyListener est nécessaire qui effectuera un setValue dans le JSpinner pour chaque clé dactylographiée.

je laisse un exemple ici pour une JSpinner avec 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
        }
    }
});
3
répondu spuas 2011-06-08 09:18:43

Il pourrait être une réponse tardive mais vous pouvez utiliser mon approche.

Comme spuas mentionné ci-dessus le problème est que stateChanged événement est tiré seulement quand la mise au point est perdue ou la touche entrée est pressée.

L'utilisation de KeyListeners n'est pas non plus une bonne idée.

Il serait préférable d'utiliser DocumentListener à la place. J'ai un peu modifié l'exemple de spuas et c'est ce que j'ai eu:

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
            }        
       }
});
2
répondu rvit34 2016-10-15 17:29:14

la dernière réponse peut être légèrement réarrangée pour la rendre un peu plus flexible. Vous pouvez simplement utiliser ce nouveau MyJSpinner à la place de n'importe quel JSpinner. Le plus grand changement est que vous pouvez utiliser cette nouvelle version avec n'importe quel modèle sous-jacent du JSpinner (int, double, octet, 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;
    }

 }
1
répondu Stephen Cuminger 2017-02-02 16:41:55

je suis nouvelle donc je pourrais enfreindre certaines règles et je pourrais être en retard. Mais j'ai trouvé certaines des réponses un peu confuses donc j'ai joué dans L'IDE de NetBeans et j'ai trouvé que si vous faites un clic droit sur le composant GUI de jspinner placé sur votre jform et allez à events-> change, le code sera généré pour vous.

0
répondu Isidore Bennett 2016-08-01 14:06:52