java swing 清除事件队列
是否可以以标准方式做到这一点?
这是场景。
开始在 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 秒”按钮。它模拟了昂贵的操作。鼠标光标将变为忙碌状态。
当光标忙碌时,单击切换按钮“Click me”。如果三秒后,切换按钮更改其状态,则切换按钮已接收鼠标事件并且未被捕获。
我希望当光标看起来很忙时,生成的鼠标(和其他)事件被丢弃。
谢谢。
Is it possible to do this in a standard manner?
Here is the scenario.
Start doing something expensive in EDT (EDT is blocked till the expensive operation is over).
While EDT was blocked, the user kept on clicking/dragging the mouse buttons. All the mouse actions are recorded somewhere.
When EDT is free (done with the expensive stuff), it starts to process the mouse events.
What I want in step 3 is to discard the mouse events that have piled up. After the EDT is free, any new mouse event should be handled in the usual manner.
Any ideas on how to achieve this.
PS: It is not possible for me to prevent the EDT from getting blocked (I do not control the behavior of some of the modules in my program).
EDIT:
If I can safely call "SunToolkit.flushPendingEvents()" then I can always put a glasspane before starting the expensive operation in EDT. After the expensive operation is over then on the EDT thread, flush all the events - they will go to a glass pane that wont do anything. And then let EDT work as normal.
EDIT2:
I have added a SSCCE to demonstrate the issue.
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; }
Run the SSCCE
Click on the button "Wait 3 seconds". It simulates an expensive operation. The mouse cursor will change to busy.
While the cursor is busy, click on the toggle button "Click me". If after three seconds, the toggle button changes its state, then the mouse event was received by the toggle button and was not trapped.
I want that while the cursor looks busy, the generated mouse (and other) events be discarded.
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
好吧,我终于把一切都搞定了。我发布 SSCCE 以获得正确工作的示例。诀窍是使用“javax.swing.SwingUtilities.invokeLater()”方法隐藏玻璃窗格。将必要的代码包装在 Runnable 中,然后使用 invokeLater 调用它。在这种情况下,Swing 会处理所有鼠标事件(因为玻璃窗格拦截了这些事件,所以什么也没发生),然后隐藏玻璃窗格。这里是 SSCCE。
再次强调,如果可能的话,不得阻止 EDT。但如果必须的话,您可以像上面那样拥有一个工作繁忙的光标。
欢迎任何评论。
OK, I finally got everything to work. I am posting the SSCCE for a correctly working example. The trick is to hide the glasspane using "javax.swing.SwingUtilities.invokeLater()" method. Wrap the necessary code in a Runnable and then invoke it using invokeLater. In such a case, Swing processes all the mouse events (nothing happens since a glasspane intercepts them), and then hides the glasspane. Here is the SSCCE.
Again, EDT if at all possible must not be blocked. But if you have to, you can have a working busy cursor as above.
Any comments are welcome.
阅读这篇文章。
基本上,长时间运行的任务不应该在 EDT 上完成。 Java 为此类任务提供了 SwingWorker。
我会更详细地讨论,但你往往不接受答案。
Read this article.
Basically, long running tasks should not be done on the EDT. Java has provided SwingWorker for tasks such as that.
I'd go into more detail, but you don't tend to accept answers.
绝对不要阻止 EDT。你绝对不应该这样做!
这是一个简单的实用程序类来执行此操作(归功于 Santosh Tiwari):
但永远不要使用它。好吧,除非您不自豪并编写了一个快速实用程序,然后失控并成为主要应用程序,并且您没有时间将代码分开来弄清楚什么可以在工作人员上运行,以及什么可以在工作人员上运行。由于与非线程安全的 swing / sql 的集成而中断。
Definitely don't block the EDT. You should never do that!
Here's an easy utility class to do this (credit to Santosh Tiwari) :
But never use it. Well, unless you're not proud and writing a quick utility that then got out of hand and became a main application, and you don't have time to pull your code apart to figure out what can run on a worker, and what would break because of integrations with swing / sql that are not thread-safe.