是否可以以标准方式执行此操作?
这是场景 .
-
开始在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 回答
阅读article .
基本上,不应该在EDT上完成长时间运行的任务 . Java为这样的任务提供了SwingWorker .
我会详细介绍,但你不倾向于接受答案 .
好的,我终于完成了一切 . 我正在发布SSCCE以获得正确的工作示例 . 诀窍是使用“javax.swing.SwingUtilities.invokeLater()”方法隐藏glasspane . 在Runnable中包装必要的代码,然后使用invokeLater调用它 . 在这种情况下,Swing处理所有鼠标事件(因为玻璃板拦截它们没有任何反应),然后隐藏玻璃板 . 这是SSCCE .
同样,EDT如果可能的话必须不被阻止 . 但是,如果必须,您可以像上面一样使用忙碌的光标 .
欢迎任何评论 .
绝对不要阻止EDT . 你永远不应该那样做!
这是一个简单的实用工具类(Santosh Tiwari):
但永远不要使用它 . 好吧,除非你不自豪并编写一个快速的实用工具然后失控并成为一个主要的应用程序,你没有时间分开你的代码来弄清楚什么可以在一个 Worker 身上运行,什么会因为与非线程安全的swing / sql集成而中断 .