6

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

这是场景。

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

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

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

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

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

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

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

EDIT2:我添加了一个 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. 当光标忙时,单击切换按钮“单击我”。如果在三秒后,切换按钮改变了它的状态,那么鼠标事件被切换按钮接收并且没有被捕获。

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

谢谢。

4

3 回答 3

5

好的,我终于让一切正常工作了。我正在发布 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。但是如果你必须这样做,你可以像上面那样有一个工作繁忙的光标。

欢迎任何意见。

于 2011-08-23T21:53:32.007 回答
2

阅读这篇文章

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

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

于 2011-08-17T15:47:57.250 回答
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;
   }

}

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

于 2018-06-28T14:42:32.720 回答