JSpinner 值更改事件

发布于 2024-09-27 22:10:10 字数 269 浏览 7 评论 0原文

当jSpinner值改变时如何立即更新。

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

spinner1.addChangeListener(listener);

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

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

り繁华旳梦境 2024-10-04 22:10:10

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

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

    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

作业与我同在 2024-10-04 22:10:10

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

附录:当 JSpinner 获得焦点时,左右箭头键会移动插入符号。向上箭头递增,向下箭头递减包含插入符号的字段。旋转器和标签中的变化(实际上)是同时发生的。

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

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

Addendum: While the JSpinner has 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.

To access the JFormattedTextField of 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.

Addendum: Update to use setCommitsOnValidEdit, as suggested 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);
    }
}
染墨丶若流云 2024-10-04 22:10:10

这可能是一个迟到的答案,但你可以使用我的方法。
正如上面提到的 spuas 问题是 stateChanged 事件仅在焦点丢失或按下 Enter 键时触发。
使用 KeyListener 也不是一个好主意。
最好使用 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
            }        
       }
});

It might be an late answer but you may use my approach.
As spuas mentioned above the problem is that stateChanged event 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 DocumentListener instead. I modified spuas's example a bit and that's what I got:

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
            }        
       }
});
趁年轻赶紧闹 2024-10-04 22:10:10

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

如果您想上传值,则需要一个 KeyListener,它将在 JSpinner 中为每个键入的键执行 setValue

我在这里留下一个带有 SpinnerNumberModelJSpinner 示例:

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

Problem here is that when you edit the JSpinner value manually by typing from the keyboard, the stateChanged event is not fired until the focus is lost by the JSpinner or until Enter key has been pressed.

If you want to upload the value, a KeyListener is needed which will perform a setValue in the JSpinner for each typed key.

I leave an example here for a JSpinner with a 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
        }
    }
});
深海夜未眠 2024-10-04 22:10:10

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

 }

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

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

 }
时光匆匆的小流年 2024-10-04 22:10:10

我通过在语句后面添加 requestFocus() 方法解决了类似的情况,如下所示:

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

希望这会是一个很好的帮助。有好的编码。

I resolved a similar situation by adding the requestFocus() method after the statement, like this:

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

Hoping this would be a good help. Have nice coding.

清风挽心 2024-10-04 22:10:10

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文