java swing清除事件队列

时间:2011-08-16 21:25:59

标签: java swing event-dispatch-thread eventqueue

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

以下是该方案。

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

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

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

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

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

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

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

    EDIT2: 我添加了一个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;
    
    }
    
    1. 运行SSCCE

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

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

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

      感谢。

3 个答案:

答案 0 :(得分:3)

好的,我终于完成了一切。我正在发布SSCCE以获得正确的工作示例。诀窍是使用“javax.swing.SwingUtilities.invokeLater()”方法隐藏玻璃板。在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。但是如果必须的话,你可以像上面那样使用忙碌的光标。

欢迎任何评论。

答案 1 :(得分:2)

阅读此article

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

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

答案 2 :(得分:1)

绝对不要阻止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;
   }

}

但是永远不要使用它。好吧,除非您不骄傲并编写一个快速的实用程序,然后该实用程序失控并成为主应用程序,并且您没有时间将代码拆开以找出可以在工作程序上运行的代码,以及由于与非线程安全的swing / sql集成而中断。