ログイン画面のあるJavaスイングアプリケーションがあります。ログイン画面には、ユーザーの資格情報が入力された後に押すための送信ボタンがあります。ボタンが押されると、ガラス ペインを使用してウィンドウ上に待機カーソルが表示されます。また、マウス操作に対して何もしないデフォルトのマウス アダプタもあります。
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() メソッドを別のスレッドで実行し、ボタンを無効にすると、マウスを複数回クリックした後に 2 つのイベントしか取得できなくなりましたが、2 つ目のイベントは依然として煩わしいものです。
コードは次のとおりです。
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);
}});
}
しかし、2 番目のイベントは引き続き発生します。私のログによると、2 番目のイベントは最初のイベントから約 280 ミリ秒後に発生しましたが、4 秒後まで実行されませんでした。 )イベントしました。
2013-11-13 10:33:57,186 [AWT-EventQueue-0] INFO carscgLoginWindow - LoginWindow.ButtonListener.actionPerformed()。2013 年 11 月 13 日 10:33:57.175 2013-11-13 10:34:01,188 [AWT-EventQueue-0] INFO carscgLoginWindow - LoginWindow.ButtonListener.actionPerformed() でイベントが発生しました。イベントは 2013 年 11 月 13 日 10:33:57.453 で発生しました
ハックして 1 秒以上前のイベントを破棄することもできると思いますが、それは見苦しく感じます。これはそれほど難しいことではないはずです、私は考え続けています。
更新 2: setEnabled() の JComponent.java からのコメント
* <p>Note: Disabling a lightweight component does not prevent it from * receiving MouseEvents.
すべての Swing コンポーネントは軽量であり、setEnabled はコンポーネントがマウス イベントを受信するのを妨げないので、何がこれを妨げますか?