JSpinner值更改事件

时间:2010-10-16 14:56:17

标签: java swing event-handling jspinner changelistener

如何在更改jSpinner值时立即进行更新。

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

spinner1.addChangeListener(listener);

上面的代码不会自动更改标签文本,它需要您再次单击任何位置进行更新。

6 个答案:

答案 0 :(得分:44)

答案是配置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并公开允许配置的方法

答案 1 :(得分:8)

您显示的代码显示正确。作为参考,这是一个工作示例。

附录:JSpinner有焦点时,左右箭头键移动插入符号。向上箭头递增,向下箭头递减包含插入符号的字段。微调器和标签中的变化(有效)同时发生。

要访问JSpinner.DateEditorJFormattedTextField,请使用父级的getTextField()方法。然后可以使用合适的插入符听众或文本输入监听器来根据需要更新标签。

附录:根据建议setCommitsOnValidEdit更新使用here

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

答案 2 :(得分: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
        }
    }
});

答案 3 :(得分:2)

这可能是一个迟到的答案,但你可以使用我的方法 正如上面提到的 spuas ,问题是只有当焦点丢失或按下Enter键时才会触发stateChanged事件。
使用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
            }        
       }
});

答案 4 :(得分:1)

最后一个答案可以重新安排一点,以使其更灵活一点。您可以简单地使用这个新的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;
    }

 }

答案 5 :(得分:0)

我是新的,所以我可能会违反一些规则而且我可能会迟到。但是我发现一些答案有点令人困惑,所以我在NetBeans IDE中玩了一下,发现如果你右键点击放在jform上的jspinner GUI组件并转到events->更改,将为您生成代码。