【发布时间】:2013-11-14 03:37:00
【问题描述】:
我有一个带有登录屏幕的 java swing 应用程序。登录屏幕有一个提交按钮,用于在输入用户凭据后按下。当按下按钮时,等待光标会使用其玻璃窗格在窗口上方抛出。还有一个默认的鼠标适配器,对任何鼠标操作都不做任何事情。
private final static MouseAdapter mouseAdapter =
new MouseAdapter() {};
/** Sets cursor for specified component to Wait cursor */
public static void startWaitCursor(JComponent component) {
log.debug("startWaitCursor()");
RootPaneContainer root =
((RootPaneContainer) component.getTopLevelAncestor());
Component glass = root.getGlassPane();
glass.setCursor(WAIT_CURSOR);
glass.addMouseListener(mouseAdapter);
glass.setVisible(true);
//force repaint of glass pane in 20ms for more responsive GUI
glass.repaint(20);
}
public static void stopWaitCursor(JComponent component) {
log.debug("stopWaitCursor()");
RootPaneContainer root =
((RootPaneContainer) component.getTopLevelAncestor());
Component glass = root.getGlassPane();
glass.setCursor(DEFAULT_CURSOR);
glass.removeMouseListener(mouseAdapter);
//force repaint of glass pane in 20ms for more responsive GUI
glass.repaint(20);
glass.setVisible(false);
}
我曾假设此设置可以在后端方法发生时保护我免受多次点击/按键的影响。我发现事实并非如此。所以在 ButtonListener.actionPerformed 中,我放了一些如下的逻辑:
static boolean waiting = false;
class ButtonListener implements ActionListener {
ButtonListener() {
super();
}
public void actionPerformed(ActionEvent e) {
log.info("LoginWindow.ButtonListener.actionPerformed()");
LoginWindow.this.repaint(50);
if (!waiting) {
try {
waiting = true;
verifyLogin();
} finally {
waiting = false;
}
}
}
}
我发现这可以保护我免受按键的影响,但不能防止鼠标点击!如果我在执行 verifyLogin() 时反复按下提交按钮,鼠标点击似乎被缓存在某处,验证登录完成后,每次鼠标点击都会被处理!
我对这里发生的事情感到非常困惑。有人有想法吗?
更新:
嗯,按照 Cyrille Ka 建议的方法:即在单独的线程中执行 verifyLogin() 方法并禁用按钮,我现在在多次鼠标单击后只收到两个事件,但第二个事件仍然很烦人。
代码现在是:
public void actionPerformed(ActionEvent e) {
loginButton.setEnabled(false);
log.infof("LoginWindow.ButtonListener.actionPerformed(). Event occurred at %1$tb %1$te %1$tY %1$tT.%1$tL",
new Date(e.getWhen()));
LoginWindow.this.repaint(50);
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
verifyLogin();
loginButton.setEnabled(true);
}});
}
但第二个事件仍然进入。我的日志显示第二个事件发生在第一个事件之后大约 280 毫秒,但直到 4 秒后才执行,尽管 setEnabled() 是第一件事actionPerformed() 事件发生了。
2013-11-13 10:33:57,186 [AWT-EventQueue-0] 信息 c.a.r.s.c.g.LoginWindow - LoginWindow.ButtonListener.actionPerformed()。事件发生在 11 月 13 日 2013 10:33:57.175 2013-11-13 10:34:01,188 [AWT-EventQueue-0] 信息 c.a.r.s.c.g.LoginWindow - LoginWindow.ButtonListener.actionPerformed()。事件发生在 11 月 13 日 2013 10:33:57.453
我想我可以做一个 hack 并丢弃第二个旧的事件或其他东西,但这感觉很难看。这应该不是那么难,我一直在想。
更新 2: 来自 JComponent.java 的 setEnabled() 注释
* <p>Note: Disabling a lightweight component does not prevent it from * receiving MouseEvents.
既然所有的 Swing 组件都是轻量级的,而且 setEnabled 不会阻止组件接收鼠标事件,那么是什么阻止了呢?
【问题讨论】:
-
您在尝试登录时尝试过
myButton.setEnabled(false);之类的方法吗? -
是的,这也不起作用。我在有和没有等待光标的情况下都试过了。在所有情况下,鼠标点击都会被存储。
-
它应该可以工作。但是,如果您不从 GUI 返回并在事件侦听器中完成工作,那么可能在事件侦听器返回之前未注册禁用。
标签: java swing jbutton actionlistener mouselistener