Java JSpinner 值更改事件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3949382/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 07:25:26  来源:igfitidea点击:

JSpinner Value change Events

javaswingevent-handlingjspinnerchangelistener

提问by user236501

How to make the update immediately when the jSpinner value was changed.

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

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

spinner1.addChangeListener(listener);

The code above doesnt change the label text automatically, it required you to click again anyplace to update.

上面的代码不会自动更改标签文本,它需要您再次单击任何地方才能更新。

回答by trashgod

The code you show appears correct. For reference, here is a working example.

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

Addendum: While the JSpinnerhas focus, the left and right arrow keys move the caret. The up arrow increments and the down arrow decrements the field containing the caret. The change is (effectively) simultaneous in both the spinner and the label.

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

To access the JFormattedTextFieldof the JSpinner.DateEditor, use the parent's getTextField()method. A suitable caret listener or text input listener may then be used to update the label as desired.

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

Addendum: Update to use setCommitsOnValidEdit, as suggested here.

附录:更新使用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);
    }
}

回答by spuas

Problem here is that when you edit the JSpinnervalue manually by typing from the keyboard, the stateChangedevent is not fired until the focus is lost by the JSpinneror until Enter key has been pressed.

这里的问题是,当您JSpinner通过从键盘输入手动编辑值时,stateChanged事件不会被触发,直到焦点丢失JSpinner或 直到按下 Enter 键。

If you want to upload the value, a KeyListeneris needed which will perform a setValuein the JSpinnerfor each typed key.

如果您想上传的值,KeyListener则需要将执行一个setValueJSpinner每个输入的密钥。

I leave an example here for a JSpinnerwith a SpinnerNumberModel:

我离开这里的例子为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
        }
    }
});

回答by kleopatra

The answer is to configure the formatter used in the JFormattedTextField which is a child of the spinner's editor:

答案是配置 JFormattedTextField 中使用的格式化程序,它是微调器编辑器的子项:

    formatter.setCommitsOnValidEdit(true);

Unfortunately, getting one's hand on it is as long and dirty as the introductory sentence:

不幸的是,接触它就像介绍性句子一样冗长和肮脏:

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

A slightly (but not by much) cleaner way might be to subclass NumberEditor and expose a method which allows the config

稍微(但不是很多)更简洁的方法可能是将 NumberEditor 子类化并公开一个允许配置的方法

回答by Isidore Bennett

I'm new so I might be breaking some rules and I might be late. But I found some of the answers a bit confusing so I played around in NetBeans IDE and found that if you right click on the jspinner GUI component placed on your jform and go to events-> change, code will be generated for you.

我是新来的,所以我可能会违反一些规则,我可能会迟到。但是我发现一些答案有点令人困惑,所以我在 NetBeans IDE 中进行了尝试,发现如果您右键单击放置在 jform 上的 jspinner GUI 组件并转到事件-> 更改,则会为您生成代码。

回答by rvit34

It might be an late answer but you may use my approach.
As spuasmentioned above the problem is that stateChangedevent is fired only when focus is lost or Enter key is pressed.
Using KeyListeners is not an good idea as well.
It would be better to use DocumentListenerinstead. I modified spuas's example a bit and that's what I got:

这可能是一个迟到的答案,但您可以使用我的方法。
正如上面提到的,问题是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
            }        
       }
});

回答by Stephen Cuminger

The last answer can be rearranged a little to make it a little more flexible. You can simply use this new MyJSpinner in place of any JSpinner. The biggest change is that you can use this new version with any underlying model of the JSpinner (int, double, byte, etc.)

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

 }