是否可以以标准方式执行此操作?
以下是该方案。
开始在EDT中做一些昂贵的事情(EDT被阻止,直到昂贵的操作结束)。
当EDT被阻止时,用户继续单击/拖动鼠标按钮。所有鼠标操作都记录在某处。
当EDT免费时(使用昂贵的东西完成),它开始处理鼠标事件。
我在步骤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; }
运行SSCCE
点击“等待3秒”按钮。它模拟了昂贵的操作。鼠标光标将变为忙碌。
光标处于忙碌状态时,单击切换按钮“Click me”。如果在三秒钟后,切换按钮改变其状态,则切换按钮接收到鼠标事件并且没有被捕获。
我希望在光标看起来很忙时,生成的鼠标(和其他)事件将被丢弃。
感谢。
答案 0 :(得分:3)
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)
答案 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集成而中断。