События изменения стоимости JSpinner
Как сделать обновление сразу после изменения значения jSpinner.
ChangeListener listener = new ChangeListener() {
public void stateChanged(ChangeEvent e) {
jLabel.setText(e.getSource());
}
};
spinner1.addChangeListener(listener);
Приведенный выше код не меняет текст ярлыка автоматически, он требует, чтобы вы снова нажимали на любое место для обновления.
Ответы
Ответ 1
Ответ заключается в настройке форматирования, используемого в JFormattedTextField, который является дочерним элементом редактора spinner:
formatter.setCommitsOnValidEdit(true);
К сожалению, получение одной руки на нее так же долго и грязно, как вводное предложение:
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());
}
});
Немного (но не намного) более чистым способом может быть подкласс NumberEditor и выставить метод, который позволяет config
Ответ 2
Код, который вы показываете, отображается правильно. Для справки, вот рабочий пример.
Приложение: В то время как JSpinner
имеет фокус, клавиши со стрелками влево и вправо перемещают курсор. Стрелка вверх увеличивается, а стрелка вниз уменьшает поле, содержащее каретку. Это изменение (эффективно) одновременно как на счетчике, так и на этикетке.
Чтобы получить доступ к JFormattedTextField
JSpinner.DateEditor
, используйте родительский getTextField()
. Подходящий прослушиватель каретки или слушатель ввода текста может затем использоваться для обновления метки по желанию.
Добавление: Обновить, чтобы использовать setCommitsOnValidEdit
, как предложено здесь.
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);
}
}
Ответ 3
Проблема заключается в том, что когда вы редактируете значение JSpinner
вручную, набрав с клавиатуры, событие stateChanged
не запускается до тех пор, пока фокус не будет потерян с помощью JSpinner
или до тех пор, пока не будет нажата клавиша Enter.
Если вы хотите загрузить значение, необходим KeyListener
, который будет выполнять setValue
в JSpinner
для каждого введенного ключа.
Я оставляю здесь пример для JSpinner
с 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
}
}
});
Ответ 4
Это может быть поздний ответ, но вы можете использовать мой подход.
Как упоминалось выше, проблема заключается в том, что событие stateChanged
запускается только тогда, когда фокус потерян или нажата клавиша Enter.
Использование KeyListeners также не является хорошей идеей.
Было бы лучше использовать DocumentListener
вместо этого. Я немного изменил пример spuas и что я получил:
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
}
}
});
Ответ 5
Я новичок, поэтому могу нарушить некоторые правила, и я могу опоздать. Но некоторые ответы я немного сбивал с толку, поэтому я играл в среде IDE NetBeans и обнаружил, что если вы щелкните правой кнопкой мыши на компоненте GUI jspinner, размещенном на вашем jform, и перейдите в event- > change, код будет создан для вас.
Ответ 6
Последний ответ можно немного перестроить, чтобы сделать его немного более гибким. Вы можете просто использовать этот новый MyJSpinner вместо любого JSpinner. Самое большое изменение заключается в том, что вы можете использовать эту новую версию с любой базовой моделью JSpinner (int, double, byte и т.д.).
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;
}
}