首页 文章

java swing清除事件队列

提问于
浏览
5

是否可以以标准方式执行此操作?

这是场景 .

  • 开始在EDT中做一些昂贵的事情(EDT被阻止,直到昂贵的操作结束) .

  • 当EDT被阻止时,用户继续单击/拖动鼠标按钮 . 所有鼠标操作都记录在某处 .

  • 当EDT是免费的(用昂贵的东西完成)时,它开始处理鼠标事件 .

我在步骤3中想要的是丢弃堆积的鼠标事件 . 在EDT免费后,任何新的鼠标事件都应该以通常的方式处理 .

关于如何实现这一点的任何想法 .

PS:我不可能阻止EDT被阻止(我不控制程序中某些模块的行为) .

编辑:如果我可以安全地调用“SunToolkit.flushPendingEvents()”,那么在开始EDT中昂贵的操作之前,我总是可以放一个玻璃板 . 在昂贵的操作结束后,在EDT线程上,清除所有事件 - 他们将进入一个不会做任何事情的玻璃窗格 . 然后让EDT正常工作 .

编辑2:我添加了一个SSCCE来证明这个问题 .

public class BusyCursorTest2 extends javax.swing.JFrame {

    public BusyCursorTest2() {

        javax.swing.JButton wait = new javax.swing.JButton("Wait 3 seconds");
        getContentPane().setLayout(new java.awt.GridLayout(2, 1, 0, 0));
        getContentPane().add(wait);
        getContentPane().add(new javax.swing.JToggleButton("Click me"));
        setTitle("Busy Cursor");
        setSize(300, 200);
        setDefaultCloseOperation(javax.swing.JFrame.DISPOSE_ON_CLOSE);
        setVisible(true);

        wait.addActionListener(new java.awt.event.ActionListener() {

            public void actionPerformed(java.awt.event.ActionEvent event) {

                final java.util.Timer timer = switchToBusyCursor(BusyCursorTest2.this);

                try {
                    //do something expensive in EDT
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        //do nothing
                    }
                } finally {
                    switchToNormalCursor(BusyCursorTest2.this, timer);
                }
            }

        });
    }

    public static java.util.Timer switchToBusyCursor(final javax.swing.JFrame frame) {
        startEventTrap(frame);
        java.util.TimerTask timerTask = new java.util.TimerTask() {

            public void run() {
                startWaitCursor(frame);
            }

        };
        final java.util.Timer timer = new java.util.Timer();
        timer.schedule(timerTask, DELAY_MS);
        return timer;
    }

    public static void switchToNormalCursor(final javax.swing.JFrame frame, final java.util.Timer timer) {
        timer.cancel();
        stopWaitCursor(frame);
        stopEventTrap(frame);
    }

    private static void startWaitCursor(javax.swing.JFrame frame) {
        frame.getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR));
        frame.getGlassPane().addMouseListener(mouseAdapter);
        frame.getGlassPane().setVisible(true);
    }

    private static void stopWaitCursor(javax.swing.JFrame frame) {
        frame.getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR));
        frame.getGlassPane().removeMouseListener(mouseAdapter);
        frame.getGlassPane().setVisible(false);
    }

    private static void startEventTrap(javax.swing.JFrame frame) {
        frame.getGlassPane().addMouseListener(mouseAdapter);
        frame.getGlassPane().setVisible(true);
    }

    private static void stopEventTrap(javax.swing.JFrame frame) {
        frame.getGlassPane().removeMouseListener(mouseAdapter);
        frame.getGlassPane().setVisible(false);
    }

    private static final java.awt.event.MouseAdapter mouseAdapter = new java.awt.event.MouseAdapter() {
    };

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                new BusyCursorTest2();
            }

        });

    }

    private static final int DELAY_MS = 250;

}
  • 运行SSCCE

  • 点击“等待3秒”按钮 . 它模拟了昂贵的操作 . 鼠标光标将变为忙碌 .

  • 光标忙时,单击切换按钮“单击我” . 如果在三秒钟后,切换按钮改变其状态,则切换按钮接收到鼠标事件并且没有被捕获 .

我希望在光标看起来很忙时,生成的鼠标(和其他)事件将被丢弃 .

谢谢 .

3 回答

  • 2

    阅读article .

    基本上,不应该在EDT上完成长时间运行的任务 . Java为这样的任务提供了SwingWorker .

    我会详细介绍,但你不倾向于接受答案 .

  • 1

    好的,我终于完成了一切 . 我正在发布SSCCE以获得正确的工作示例 . 诀窍是使用“javax.swing.SwingUtilities.invokeLater()”方法隐藏glasspane . 在Runnable中包装必要的代码,然后使用invokeLater调用它 . 在这种情况下,Swing处理所有鼠标事件(因为玻璃板拦截它们没有任何反应),然后隐藏玻璃板 . 这是SSCCE .

    public class BusyCursorTest2 extends javax.swing.JFrame {
    
        public BusyCursorTest2() {
    
            javax.swing.JButton wait = new javax.swing.JButton("Wait 3 seconds");
            getContentPane().setLayout(new java.awt.GridLayout(2, 1, 0, 0));
            getContentPane().add(wait);
            getContentPane().add(new javax.swing.JToggleButton("Click me"));
            setTitle("Busy Cursor");
            setSize(300, 200);
            setDefaultCloseOperation(javax.swing.JFrame.DISPOSE_ON_CLOSE);
            setVisible(true);
    
            wait.addActionListener(new java.awt.event.ActionListener() {
    
                public void actionPerformed(java.awt.event.ActionEvent event) {
    
                    final java.util.Timer timer = switchToBusyCursor(BusyCursorTest2.this);
    
                    try {
                        //do something expensive in EDT or otherwise
                        try {
                            Thread.sleep(3000);
                        } catch (InterruptedException e) {
                            //do nothing
                        }
                    } finally {
                        switchToNormalCursorEventThread(BusyCursorTest2.this, timer);
                    }
    
                }
    
            });
        }
    
        public static java.util.Timer switchToBusyCursor(final javax.swing.JFrame frame) {
            startEventTrap(frame);
            java.util.TimerTask timerTask = new java.util.TimerTask() {
    
                public void run() {
                    startWaitCursor(frame);
                }
    
            };
            final java.util.Timer timer = new java.util.Timer();
            timer.schedule(timerTask, DELAY_MS);
            return timer;
        }
    
        public static void switchToNormalCursorEventThread(final javax.swing.JFrame frame, final java.util.Timer timer) {
    
            Runnable r = new Runnable() {
    
                public void run() {
                    switchToNormalCursor(frame, timer);
                }
    
            };
    
            javax.swing.SwingUtilities.invokeLater(r);
    
        }
    
        public static void switchToNormalCursor(final javax.swing.JFrame frame, final java.util.Timer timer) {
            timer.cancel();
            stopWaitCursor(frame);
            stopEventTrap(frame);
        }
    
        private static void startWaitCursor(javax.swing.JFrame frame) {
            frame.getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR));
            frame.getGlassPane().addMouseListener(mouseAdapter);
            frame.getGlassPane().setVisible(true);
        }
    
        private static void stopWaitCursor(javax.swing.JFrame frame) {
            frame.getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR));
            frame.getGlassPane().removeMouseListener(mouseAdapter);
            frame.getGlassPane().setVisible(false);
        }
    
        private static void startEventTrap(javax.swing.JFrame frame) {
            frame.getGlassPane().addMouseListener(mouseAdapter);
            frame.getGlassPane().setVisible(true);
        }
    
        private static void stopEventTrap(javax.swing.JFrame frame) {
            java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue();
            frame.getGlassPane().removeMouseListener(mouseAdapter);
            frame.getGlassPane().setVisible(false);
        }
    
        private static final java.awt.event.MouseAdapter mouseAdapter = new java.awt.event.MouseAdapter() {
        };
    
        public static void main(String[] args) {
            javax.swing.SwingUtilities.invokeLater(new Runnable() {
    
                public void run() {
                    new BusyCursorTest2();
                }
    
            });
    
        }
    
        private static final int DELAY_MS = 250;
    
    }
    

    同样,EDT如果可能的话必须不被阻止 . 但是,如果必须,您可以像上面一样使用忙碌的光标 .

    欢迎任何评论 .

  • 3

    绝对不要阻止EDT . 你永远不应该那样做!

    这是一个简单的实用工具类(Santosh Tiwari):

    import java.awt.Component;
    import java.awt.Cursor;
    import java.awt.Toolkit;
    import java.awt.Window;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.Timer;
    import java.util.TimerTask;
    
    import javax.swing.JDialog;
    import javax.swing.JFrame;
    import javax.swing.SwingUtilities;
    
    /**
     * When blocking the EDT (Event Queue) in swing, the cursor won't update, and windows won't render.
     * This should show the hourglass even when you're blocking the EDT.
     *
     * Source:
     * https://stackoverflow.com/questions/7085239/java-swing-clear-the-event-queue
     * 
     * @author Kieveli, Santosh Tiwari
     *
     */
    public class BlockingWaitCursor {
    
       private static final java.awt.event.MouseAdapter mouseAdapter = new java.awt.event.MouseAdapter() {};
    
       /**
        * The Dialog or main window is required to show the cursor and animate it. The actionListener is called
        * as soon as initial setup is completed and the animation timer is running.
        * @param currentComponent A panel, dialog, frame, or any other swing component that is the current focus
        * @param action Your action to perform on the EDT. This is started extremely quickly and without delay.
        */
       public static void showWaitAndRun(Component currentComponent, ActionListener action ) {
    
          Timer timer = setupWaitCursor(currentComponent);
    
          try {
             // now allow our caller to execute their slow and delayed code on the EDT
             ActionEvent event = new ActionEvent(BlockingWaitCursor.class, ActionEvent.ACTION_PERFORMED, "run");
             action.actionPerformed(event);
          }
          finally {
             resetWaitCursor(currentComponent, timer);
          }
       }
    
       private static Timer setupWaitCursor(Component currentComponent) {
          final Component glassPane = findGlassPane(currentComponent);
          if ( glassPane == null ) {
             return null;
          }
    
          // block mouse-actions with a glass pane that covers everything
          glassPane.addMouseListener(mouseAdapter);
          glassPane.setVisible(true);
    
          // animate the wait cursor off of the EDT using a generic timer.
          Timer timer = new Timer();
          timer.schedule( new TimerTask() {
             @Override
             public void run() {
                glassPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
                glassPane.addMouseListener(mouseAdapter);
                glassPane.setVisible(true);
             }
    
          }, 250l);
    
          return timer;
       }
    
       private static void resetWaitCursor(Component currentComponent, final Timer timer) {
          final Component glassPane = findGlassPane(currentComponent);
          if ( glassPane == null ) {
             return;
          }
          // Invoke later so that the event queue contains user actions to cancel while the loading occurred
          SwingUtilities.invokeLater(new Runnable() {
             @Override
             public void run() {
                if ( timer != null )
                   timer.cancel();
                Toolkit.getDefaultToolkit().getSystemEventQueue();
                glassPane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
                glassPane.removeMouseListener(mouseAdapter);
                glassPane.setVisible(false);  
             }
          });
       }
    
       private static Component findGlassPane(Component currentComponent) {
          // try to locate the glass pane by looking for a frame or dialog as an ancestor
          JFrame frame = findFrame(currentComponent);
          JDialog dialog = findDialog(currentComponent);
          Component glassPane = null;
          if ( frame != null )
             glassPane = frame.getGlassPane();
          if ( dialog != null )
             glassPane = dialog.getGlassPane();
          return glassPane;
       }
    
       private static JFrame findFrame(Component currentComponent) {
          // find the frame if it exists - it may be the currentComponent
          if ( currentComponent instanceof JFrame )
             return (JFrame) currentComponent;
    
          Window window = SwingUtilities.getWindowAncestor(currentComponent);
          if ( window == null )
             return null;
          if ( ! (window instanceof JFrame) )
             return null;
          return (JFrame)window;
       }
    
       private static JDialog findDialog(Component currentComponent) {
          // find the dialog if it exists - it may be the currentComponent
          if ( currentComponent instanceof JDialog )
             return (JDialog) currentComponent;
    
          Window window = SwingUtilities.getWindowAncestor(currentComponent);
          if ( window == null )
             return null;
          if ( ! (window instanceof JDialog) )
             return null;
          return (JDialog)window;
       }
    
    }
    

    但永远不要使用它 . 好吧,除非你不自豪并编写一个快速的实用工具然后失控并成为一个主要的应用程序,你没有时间分开你的代码来弄清楚什么可以在一个 Worker 身上运行,什么会因为与非线程安全的swing / sql集成而中断 .

相关问题