JSpinner stateChanged是如何工作的?

时间:2013-10-03 17:59:53

标签: java swing jspinner changelistener

为什么代码在JSpinner的change事件中输入两次?

private javax.swing.JSpinner spinner = new javax.swing.JSpinner()
spinner.setModel(new javax.swing.SpinnerDateModel());
    spinner.addChangeListener(new javax.swing.event.ChangeListener() {
        @Override
        public void stateChanged(javax.swing.event.ChangeEvent evt) {
            System.out.println("Just a test");
        }
    });

当您只点击一次时,上面的代码会显示两次消息。

2 个答案:

答案 0 :(得分:3)

生成2个事件:一个用于取消选择的值,另一个用于在组件中选择的新值。正如@camickr在他的评论中指出的那样,此行为发生在SpinnerDateModel中,但不会出现在默认SpinnerNumberModel

作为解决方法,您可以使用

spinner.addChangeListener(new ChangeListener() {

    Object lastValue;

    @Override
    public void stateChanged(ChangeEvent evt) {

        if (lastValue != null && !spinner.getValue().equals(lastValue)) {
           // expensive code calls here!
        }
        lastValue = spinner.getValue();
    }
});

这不会阻止侦听器被调用两次,但阻止不必要地调用任何昂贵的代码

答案 1 :(得分:0)

碰到相同的问题并找到了不同的解决方法,因为https://stackoverflow.com/a/19166589/5326620中的一个方法导致在直接直接在文本字段上编辑日期时错过了该事件。

在我的情况下,我将SpinnerDateModel用于Calendar.DAY_OF_MONTH(与Calendar.DATE相同)。 如果SpinnerDateModel恰好在午夜初始化了一个值,则该事件不再触发两次。

Calendar now = Calendar.getInstance();
now.set(Calendar.HOUR, 0);
now.set(Calendar.MINUTE, 0);
now.set(Calendar.SECOND, 0);
now.set(Calendar.MILLISECOND, 0);
Date value = now.getTime();
JSpinner dateSpn = new JSpinner(new SpinnerDateModel(value, null, null, Calendar.DAY_OF_MONTH));

这可能是因为JFormattedTextField的commitEdit通过相等性测试旧值和新值,而Date相等性是毫秒。