【问题标题】:java swing clear the event queuejava swing清除事件队列
【发布时间】:2011-10-28 10:52:07
【问题描述】:

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

这是场景。

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

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

  3. 当 EDT 空闲时(用昂贵的东西完成),它开始处理鼠标事件。

我想要在第 3 步中丢弃堆积的鼠标事件。在 EDT 空闲后,任何新的鼠标事件都应该以通常的方式处理。

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

PS:我无法阻止 EDT 被阻塞(我无法控制程序中某些模块的行为)。

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

编辑2: 我添加了一个 SSCCE 来演示这个问题。

公共类 BusyCursorTest2 扩展 javax.swing.JFrame { 公共 BusyCursorTest2() { javax.swing.JButton wait = new javax.swing.JButton("等待 3 秒"); getContentPane().setLayout(new java.awt.GridLayout(2, 1, 0, 0)); getContentPane().add(等待); getContentPane().add(new javax.swing.JToggleButton("点击我")); setTitle("忙碌光标"); 设置大小(300、200); setDefaultCloseOperation(javax.swing.JFrame.DISPOSE_ON_CLOSE); 设置可见(真); wait.addActionListener(new java.awt.event.ActionListener() { 公共无效actionPerformed(java.awt.event.ActionEvent事件){ final java.util.Timer timer = switchToBusyCursor(BusyCursorTest2.this); 尝试 { //在 EDT 中做一些昂贵的事情 尝试 { 线程.sleep(3000); } 捕捉(InterruptedException e){ //没做什么 } } 最后 { switchToNormalCursor(BusyCursorTest2.this, timer); } } }); } 公共静态 java.util.Timer switchToBusyCursor(final javax.swing.JFrame frame) { 开始事件陷阱(帧); java.util.TimerTask timerTask = new java.util.TimerTask() { 公共无效运行(){ startWaitCursor(帧); } }; final java.util.Timer timer = new java.util.Timer(); timer.schedule(timerTask, DELAY_MS); 返回计时器; } public static void switchToNormalCursor(final javax.swing.JFrame frame, final java.util.Timer timer) { 计时器.取消(); 停止等待光标(帧); 停止事件陷阱(帧); } 私有静态无效 startWaitCursor(javax.swing.JFrame 框架) { frame.getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR)); frame.getGlassPane().addMouseListener(mouseAdapter); frame.getGlassPane().setVisible(true); } 私有静态无效 stopWaitCursor(javax.swing.JFrame 框架) { frame.getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR)); frame.getGlassPane().removeMouseListener(mouseAdapter); frame.getGlassPane().setVisible(false); } 私有静态无效 startEventTrap(javax.swing.JFrame 框架){ frame.getGlassPane().addMouseListener(mouseAdapter); frame.getGlassPane().setVisible(true); } 私有静态无效stopEventTrap(javax.swing.JFrame框架){ frame.getGlassPane().removeMouseListener(mouseAdapter); frame.getGlassPane().setVisible(false); } 私有静态最终 java.awt.event.MouseAdapter mouseAdapter = new java.awt.event.MouseAdapter() { }; 公共静态无效主要(字符串[]参数){ javax.swing.SwingUtilities.invokeLater(new Runnable() { 公共无效运行(){ 新的 BusyCursorTest2(); } }); } 私有静态最终 int DELAY_MS = 250; }
  1. 运行 SSCCE

  2. 单击“等待 3 秒”按钮。它模拟了昂贵的操作。鼠标光标将变为忙碌状态。

  3. 当光标处于忙碌状态时,单击切换按钮“单击我”。如果在三秒后,切换按钮改变了状态,那么鼠标事件被切换按钮接收到并且没有被捕获。

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

谢谢。

【问题讨论】:

  • 不,大多数swing组件(所有不同的面板及其内容等)都是由不同的开发人员完成的,并且可能随时更改。我无法对这些摆动组件做出任何假设。我只能在 rootpane 上制作可见的 glasspane 以防止他们获取事件。
  • 您有两种解决方案。 1)将昂贵的操作放在工作线程上。 2) 使用玻璃板阻止其他事件。 Swing 并非旨在保护应用免受开发人员的侵害。
  • 不是从 EventQueue 更改或拆分一致性的好方法,但通过在此论坛中进行最深入的搜索 EventQueue theQueue = getToolkit().getSystemEventQueue(); 不要明白,如果您手动将任何事件发送到 EDT,所有等待线程都会迷失了,永远停留在现在的形式,干脆不要那样做,
  • 1) 不要 2) 不要 3) 不要 - 或者换句话说:与其花心思去做一些令人难以置信的反摇摆的事情,不如把所有的精力都放在说服谁负责,这是一个 no-no-never-ever,它将在未来的任何时候产生不可预测的维护痛苦

标签: java swing event-dispatch-thread eventqueue


【解决方案1】:

好的,我终于可以正常工作了。我正在发布 SSCCE 以获得正确工作的示例。诀窍是使用“javax.swing.SwingUtilities.invokeLater()”方法隐藏玻璃窗格。将必要的代码包装在 Runnable 中,然后使用 invokeLater 调用它。在这种情况下,Swing 会处理所有的鼠标事件(因为 glasspane 拦截了它们,所以什么都不会发生),然后隐藏 glasspane。这里是 SSCCE。

公共类 BusyCursorTest2 扩展 javax.swing.JFrame { 公共 BusyCursorTest2() { javax.swing.JButton wait = new javax.swing.JButton("等待 3 秒"); getContentPane().setLayout(new java.awt.GridLayout(2, 1, 0, 0)); getContentPane().add(等待); getContentPane().add(new javax.swing.JToggleButton("点击我")); setTitle("忙碌光标"); 设置大小(300、200); setDefaultCloseOperation(javax.swing.JFrame.DISPOSE_ON_CLOSE); 设置可见(真); wait.addActionListener(new java.awt.event.ActionListener() { 公共无效actionPerformed(java.awt.event.ActionEvent事件){ final java.util.Timer timer = switchToBusyCursor(BusyCursorTest2.this); 尝试 { //在 EDT 或其他方面做一些昂贵的事情 尝试 { 线程.sleep(3000); } 捕捉(InterruptedException e){ //没做什么 } } 最后 { switchToNormalCursorEventThread(BusyCursorTest2.this, timer); } } }); } 公共静态 java.util.Timer switchToBusyCursor(final javax.swing.JFrame frame) { 开始事件陷阱(帧); java.util.TimerTask timerTask = new java.util.TimerTask() { 公共无效运行(){ startWaitCursor(帧); } }; final java.util.Timer timer = new java.util.Timer(); timer.schedule(timerTask, DELAY_MS); 返回计时器; } 公共静态无效 switchToNormalCursorEventThread(最终 javax.swing.JFrame 帧,最终 java.util.Timer 计时器){ 可运行 r = new Runnable() { 公共无效运行(){ switchToNormalCursor(帧,计时器); } }; javax.swing.SwingUtilities.invokeLater(r); } public static void switchToNormalCursor(final javax.swing.JFrame frame, final java.util.Timer timer) { 计时器.取消(); 停止等待光标(帧); 停止事件陷阱(帧); } 私有静态无效 startWaitCursor(javax.swing.JFrame 框架) { frame.getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR)); frame.getGlassPane().addMouseListener(mouseAdapter); frame.getGlassPane().setVisible(true); } 私有静态无效 stopWaitCursor(javax.swing.JFrame 框架) { frame.getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR)); frame.getGlassPane().removeMouseListener(mouseAdapter); frame.getGlassPane().setVisible(false); } 私有静态无效 startEventTrap(javax.swing.JFrame 框架){ frame.getGlassPane().addMouseListener(mouseAdapter); frame.getGlassPane().setVisible(true); } 私有静态无效stopEventTrap(javax.swing.JFrame框架){ java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue(); frame.getGlassPane().removeMouseListener(mouseAdapter); frame.getGlassPane().setVisible(false); } 私有静态最终 java.awt.event.MouseAdapter mouseAdapter = new java.awt.event.MouseAdapter() { }; 公共静态无效主要(字符串[]参数){ javax.swing.SwingUtilities.invokeLater(new Runnable() { 公共无效运行(){ 新的 BusyCursorTest2(); } }); } 私有静态最终 int DELAY_MS = 250; }

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

欢迎任何cmets。

【讨论】:

    【解决方案2】:

    阅读此article

    基本上,不应在 EDT 上执行长时间运行的任务。 Java 为此类任务提供了 SwingWorker。

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

    【讨论】:

    • 我在自己的代码中使用 SwingWorker(自定义实现,因为我的代码应该与 JAVA 1.5 兼容)。这是我无法控制的其他代码。谢谢你的回答。
    • 好吧,我回去接受了我的问题的答案(其中一些是我自己回答的,所以我仍然接受了)。对于那些我从其他帖子中获得帮助的帖子,我会返回并在我记得的任何地方点赞。
    【解决方案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 集成而中断。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-10
      相关资源
      最近更新 更多