有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Swing会在减少Windows时间后忽略第一次单击

我有一个处理日期和时间的Swing应用程序,所以很多测试都是通过更改系统的日期和时间设置来完成的。 在测试过程中,我们注意到在降低时钟后,应用程序会忽略第一次单击

这是Swing/Java/Windows的一个bug吗?有解决办法吗

有趣的是,此问题仅在减少日期/时间设置时发生。如果我增加它,应用程序将正常运行

情况:

  • 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) 个答案

  1. # 1 楼答案

    如图所示hereSwing使用日期来检查事件发生的时间。所以,在某种程度上,可能是一个处理程序在这里通过对你的动作进行划分来进行操作,因为它发生在最后一个动作之前。我不能向您确认这一点,但可能有一些布局管理器或其他处理程序正在处理一些事情,以防止延迟事件扰乱当前流

  2. # 2 楼答案

    我已经通过Eclipse对其进行了调试,并发现了正在发生的事情

    • 15点钟
    • 点击按钮。将上次事件时间记录到15:00
    • 把钟改到14点
    • 点击按钮。Swing会忽略该事件,因为它看起来像是多次单击

    这里的问题是,通过多点单击的Swing检查进行的比较如下:

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

    这里,currentTime - lastTime产生一个负值。它小于0(mymultiClickThreshhold),因此不会触发操作事件:

    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,但是如果threshold小于0,它会抛出IllegalArgumentException

    因此,作为一种解决方法,我做了以下工作:

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