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