4

我有一个处理日期和时间的 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);
                }
            });
        }

    }
4

2 回答 2

1

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

于 2011-09-28T14:46:03.673 回答
0

我已经通过 Eclipse 对其进行了调试,并发现了发生了什么。

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

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

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

在这里,currentTime - lastTime产生一个负值。它小于0(my 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);
    }

}
于 2011-09-29T11:34:40.650 回答