JSpinner Значение изменения События

Как сделать обновление сразу после изменения значения jSpinner.

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

spinner1.addChangeListener(listener);

Приведенный выше код не изменяет текст метки автоматически, он требует повторного нажатия в любом месте для обновления.

7 ответов

Ответ заключается в настройке форматера, используемого в JFormattedTextField, который является потомком редактора счетчика:

    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 и предоставлении метода, который позволяет конфигурации

Код, который вы показываете, отображается правильно. Для справки вот рабочий пример.

Приложение: пока 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://stackru.com/questions/2010819
 * @see https://stackru.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);
    }
}

Проблема здесь в том, что при редактировании 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
        }
    }
});

Это может быть поздний ответ, но вы можете использовать мой подход.
Как упоминалось выше, проблема заключается в том, что 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
            }        
       }
});

Последний ответ можно немного изменить, чтобы сделать его более гибким. Вы можете просто использовать этот новый 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;
    }

 }

Я решил аналогичную ситуацию, добавив метод requestFocus() после оператора, например:

      spinner.addChangeListener(new ChangeListener() {
    @Override
    public void stateChanged(ChangeEvent e) {
        //Do what you need
        spinner.requestFocus();
    }
}

Надеясь, что это будет хорошей помощью. Приятного кодирования.

Я новичок, поэтому могу нарушить некоторые правила и опоздать. Но некоторые ответы показались мне немного запутанными, поэтому я поиграл в IDE NetBeans и обнаружил, что если вы щелкнете правой кнопкой мыши на компоненте GUI jspinner, размещенном на вашем jform, и перейдете в раздел events-> change, для вас будет сгенерирован код.

Другие вопросы по тегам