减少Windows时间后,Swing忽略第一次单击

时间:2011-09-28 14:34:50

标签: java windows swing date java-5

我有一个处理日期和时间的Swing应用程序,所以很多测试都在改变系统的日期和时间设置。 在测试期间,我们注意到在减少时钟后,应用程序将忽略第一次单击。

是Swing / Java / Windows的错误吗?有解决方法吗?

有趣的是,只有在减少日期/时间设置时才会出现此问题。如果我增加它,应用程序就会正常运行。

情况:

  • Swing应用程序正在运行。
  • 减少Windows日期和时间设置(例如,将时间从15:00更改为14:00)。
  • 请注意,Swing应用程序中的第一次单击不会触发任何操作。

代码示例(您可以使用它来证明情况):

    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;

    import javax.swing.JButton;
    import javax.swing.JFrame;

    public class Main {

        public static void main(String[] args) {
            final JFrame frame = new JFrame("frame");
            final JButton button = new JButton("button");
            button.addActionListener(new ActionListener() {

                public void actionPerformed(final ActionEvent e) {
                    System.out.println("Button Pressed!");
                }
            });

            frame.add(button);
            frame.setSize(200, 200);
            frame.setVisible(true);
            frame.addWindowListener(new WindowAdapter() {

                @Override
                public void windowClosing(final WindowEvent e) {
                    System.exit(0);
                }
            });
        }

    }

2 个答案:

答案 0 :(得分:1)

如所见here,Swing使用日期来检查事件何时发生。因此,在某种程度上,通过放弃您的操作,处理程序在此处起作用,因为它发生在“最后一个操作之前”。我无法确认你这一点,但是有些布局管理器或其他处理程序在这里搞乱了一些东西,以防止延迟事件搞乱当前流程。

答案 1 :(得分:0)

我已经通过Eclipse调试它并发现了正在发生的事情。

  • 时钟15:00h。
  • 点击按钮。 Swing记录上次活动时间至15:00。
  • 将时钟更改为14:00h。
  • 点击按钮。 Swing忽略该事件,因为它看起来像是一个多击。

这里的问题是Swing检查多次点击所做的比较是这样的:

if (lastTime != -1 && currentTime - lastTime < multiClickThreshhold) {
    shouldDiscardRelease = true;

此处,currentTime - lastTime产生负值。它小于0(我的multiClickThreshhold),因此它不会触发操作事件:

public void mouseReleased(MouseEvent e) {
    if (SwingUtilities.isLeftMouseButton(e)) {
        // Support for multiClickThreshhold
        if (shouldDiscardRelease) {
            shouldDiscardRelease = false;
            return;
        }
        AbstractButton b = (AbstractButton) e.getSource();
        ButtonModel model = b.getModel();
        model.setPressed(false);
        model.setArmed(false);
    }
}

上面列出的所有来源都在javax.swing.plaf.basic.BasicButtonListener

Button类确实有setMultiClickThreshhold,但如果阈值小于IllegalArgumentException,它会抛出0

所以,作为一种解决方法,我这样做了:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.lang.reflect.Field;

import javax.swing.AbstractButton;
import javax.swing.JButton;
import javax.swing.JFrame;

public class Main {

    public static void main(String[] args) throws Exception {
        final JFrame frame = new JFrame("frame");
        final JButton button = new JButton("button");
        removeMulticlickThreshold(button);

        button.addActionListener(new ActionListener() {

            public void actionPerformed(final ActionEvent e) {
                System.out.println("Button Pressed!");
            }
        });

        frame.add(button);
        frame.setSize(200, 200);
        frame.setVisible(true);
        frame.addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(final WindowEvent e) {
                System.exit(0);
            }
        });
    }

    private static void removeMulticlickThreshold(final JButton button) throws Exception {
        final Field multiClickThreshhold = AbstractButton.class.getDeclaredField("multiClickThreshhold");
        multiClickThreshhold.setAccessible(true);
        multiClickThreshhold.set(button, Long.MIN_VALUE);
    }

}