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