Cursorを砂時計に変更
Total: 29523
, Today: 3
, Yesterday: 3
Posted by aterai at
Last-modified:
概要
バックグラウンドで処理が実行されている間は、Cursor
に砂時計が設定されたGlassPane
を有効にします。
Screenshot
Advertisement
サンプルコード
frame.setGlassPane(new LockingGlassPane());
frame.getGlassPane().setVisible(false);
button.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
frame.getGlassPane().setVisible(true);
button.setEnabled(false);
new SwingWorker() {
@Override public Object doInBackground() {
doSomeLongTask();
return "Done";
}
@Override public void done() {
frame.getGlassPane().setVisible(false);
button.setEnabled(true);
}
}.execute();
}
});
// ...
class LockingGlassPane extends JComponent {
public LockingGlassPane() {
setOpaque(false);
setFocusTraversalPolicy(new DefaultFocusTraversalPolicy() {
@Override public boolean accept(Component c) {
return false;
}
});
addKeyListener(new KeyAdapter() {});
addMouseListener(new MouseAdapter() {});
requestFocusInWindow();
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
@Override public void setVisible(boolean flag) {
super.setVisible(flag);
setFocusTraversalPolicyProvider(flag);
}
}
View in GitHub: Java, Kotlin解説
上記のサンプルでは、カーソルを砂時計に変更し、なにもしないマウスリスナーなどを設定したGlassPane
をJFrame#setGlassPane()
メソッドでフレームに追加しています。
スタートボタンがクリックされて処理が継続している間はこのGlassPane
が有効になり、マウス、キー入力、フォーカス移動などのイベントがすべてGlassPane
に奪われるため、フレーム内のコンポーネントがアクセス不可状態になります。
このため、サンプルにあるsetEnabled(true)
なJTextField
の上にマウスポインタを移動しても処理中はカーソルアイコンは砂時計のまま変化しません。
Tabキーなどによるフォーカス移動を禁止する場合は、GlassPane
に以下のような設定を行います。
- どのコンポーネントにもフォーカス移動できない
FocusTraversalPolicy
を設定する
setFocusTraversalPolicy(new DefaultFocusTraversalPolicy() {
@Override public boolean accept(Component c) {
return false;
}
});
- または、
TraversalKeys
を空にする
Set<AWTKeyStroke> s = Collections.emptySet();
setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, s);
setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, s);
Mnemonic
なども禁止したい場合は、以下のようなGlassPane
を使用する方法があります(参考: Disabling Swing Containers, the final solution?)。
class LockingGlassPane extends JComponent {
public LockingGlassPane() {
setOpaque(false);
super.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
@Override public void setVisible(boolean isVisible) {
boolean oldVisible = isVisible();
super.setVisible(isVisible);
JRootPane rootPane = SwingUtilities.getRootPane(this);
if (rootPane != null && isVisible() != oldVisible) {
rootPane.getLayeredPane().setVisible(!isVisible);
}
}
@Override protected void paintComponent(Graphics g) {
JRootPane rootPane = SwingUtilities.getRootPane(this);
if (rootPane != null) {
// http://weblogs.java.net/blog/alexfromsun/archive/2008/01/
// it is important to call print() instead of paint() here
// because print() doesn't affect the frame's double buffer
rootPane.getLayeredPane().print(g);
}
super.paintComponent(g);
}
}
JDK 1.6.0
の場合、Disabled Glass Pane « Java Tips Weblogのようにキー入力を無効にするキーリスナーを追加する方法もある- この方法は、
JDK 1.5.0
などの場合、WindowsLookAndFeel
で、Altキーを押すとメニューバーにフォーカスが移動する場合がある
- この方法は、
JDK 1.7.0
の場合、JLayer
を使用して特定のコンポーネントだけ入力不可、かつカーソルを砂時計に変更するなどの設定が可能になった
参考リンク
- Swing - How to display "Loading data..." to the user
- Disabling Swing Containers, the final solution?
- Disabled Glass Pane « Java Tips Weblog