web-dev-qa-db-fra.com

JSpinner événements de changement de valeur

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

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

spinner1.addChangeListener(listener);

Le code ci-dessus ne change pas le texte de l'étiquette automatiquement, vous devez cliquer à nouveau n'importe où pour mettre à jour. 

34
user236501

La solution consiste à configurer le formateur utilisé dans JFormattedTextField, qui est un enfant de l'éditeur de spinner:

    formatter.setCommitsOnValidEdit(true);

Malheureusement, mettre la main dessus est aussi long et aussi 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());
        }
    });

Une manière légèrement (mais pas beaucoup) plus propre peut être de sous-classer NumberEditor et d’exposer une méthode qui permet

45
kleopatra

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

Addendum: Alors que la variable JSpinner a le focus, les touches fléchées gauche et droite déplacent le curseur. La flèche vers le haut augmente et la flèche vers le bas décrémente le champ contenant le curseur. Le changement est (effectivement) simultané à la fois dans la roulette et sur l’étiquette.

Pour accéder à la JFormattedTextField du JSpinner.DateEditor , utilisez la méthode getTextField() du parent. Un auditeur approprié ou un auditeur de saisie de texte peut ensuite être utilisé pour mettre à jour l'étiquette comme souhaité.

Addendum: Mise à jour pour utiliser setCommitsOnValidEdit , comme 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
trashgod

Le problème est que lorsque vous modifiez manuellement la valeur JSpinner en le saisissant au clavier, l'événement stateChanged n'est déclenché que lorsque la JSpinner a perdu le focus ou que l'utilisateur a appuyé sur la touche Entrée.

Si vous souhaitez télécharger la valeur, il vous faut une KeyListener qui effectuera une setValue dans la JSpinner pour chaque clé saisie.

Je laisse un exemple ici pour une JSpinner avec une 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
spuas

C'est peut-être une réponse tardive, mais vous pouvez utiliser mon approche.
Comme spuas mentionné ci-dessus, le problème est que l'événement stateChanged est déclenché uniquement lorsque la mise au point est perdue ou que vous appuyez sur la touche Entrée.
Utiliser KeyListeners n’est pas une bonne idée aussi.
Il serait préférable d’utiliser DocumentListener à la place. J'ai modifié un peu l'exemple de spuas et c'est ce que j'ai obtenu: 

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
rvit34

La dernière réponse peut être légèrement modifiée pour la rendre un peu plus flexible. Vous pouvez simplement utiliser ce nouveau MyJSpinner à la place de n’importe quel JSpinner. Le plus gros changement est que vous pouvez utiliser cette nouvelle version avec n’importe quel modèle sous-jacent de 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
Stephen Cuminger

Je suis nouveau, je risque donc d'enfreindre certaines règles et d'être en retard. Mais comme certaines des réponses étaient un peu déroutantes, j’ai joué dans NetBeans IDE et constaté que si vous faites un clic droit sur le composant GUI jspinner placé sur votre jform et que vous accédez à events-> change, du code sera généré vous. 

0
Isidore Bennett