Swing/WaitCursor のバックアップの現在との差分(No.1)
TITLE:Cursorを砂時計に変更
Cursorを砂時計に変更
編集者:Terai Atsuhiro~
作成日:2004-06-07
更新日:2024-02-05 (月) 15:47:59
概要
バックグラウンドで処理が実行されている間は、Cursor
に砂時計が設定されたGlassPane
を有効にします。
Screenshot
Advertisement
概要
処理中、マウスカーソルを砂時計に変更します。サンプルコード
#spanend
#spanadd
frame.setGlassPane(new LockingGlassPane());
#spanend
#spanadd
frame.getGlassPane().setVisible(false);
#spanend
#spanadd
button.addActionListener(new ActionListener() {
#spanend
@Override public void actionPerformed(ActionEvent e) {
frame.getGlassPane().setVisible(true);
button.setEnabled(false);
new SwingWorker() {
@Override public Object doInBackground() {
doSomeLongTask();
return "Done";
}
#spandel
#screenshot
#spanend
@Override public void done() {
frame.getGlassPane().setVisible(false);
button.setEnabled(true);
}
}.execute();
}
#spanadd
});
#spanend
#spanadd
// ...
#spanend
#spanadd
class LockingGlassPane extends JComponent {
#spanend
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));
}
#spandel
**サンプルコード [#r111147b]
#spanend
@Override public void setVisible(boolean flag) {
super.setVisible(flag);
setFocusTraversalPolicyProvider(flag);
}
#spanadd
}
#spanend
#spanadd
View in GitHub: Java, Kotlin解説
上記のサンプルでは、カーソルを砂時計に変更し、なにもしないマウスリスナーなどを設定したGlassPane
をJFrame#setGlassPane()
メソッドでフレームに追加しています。
スタートボタンがクリックされて処理が継続している間はこのGlassPane
が有効になり、マウス、キー入力、フォーカス移動などのイベントがすべてGlassPane
に奪われるため、フレーム内のコンポーネントがアクセス不可状態になります。
このため、サンプルにあるsetEnabled(true)
なJTextField
の上にマウスポインタを移動しても処理中はカーソルアイコンは砂時計のまま変化しません。
- -
Tabキーなどによるフォーカス移動を禁止する場合は、
GlassPane
に以下のような設定を行います。
- どのコンポーネントにもフォーカス移動できない
FocusTraversalPolicy
を設定する
frame.setGlassPane(new MyGlassPane());
frame.getGlassPane().setVisible(false);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frame.getGlassPane().setVisible(true);
button.setEnabled(false);
frame.setFocusTraversalPolicy(policy);
Thread t = new Thread(new Runnable() {
public void run() {
longTask();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.getGlassPane().setVisible(false);
button.setEnabled(true);
frame.setFocusTraversalPolicy(ftp);
}
});
}
});
//t.setPriority(Thread.MIN_PRIORITY);
t.start();
}
});
#spanadd
setFocusTraversalPolicy(new DefaultFocusTraversalPolicy() {
#spanend
@Override public boolean accept(Component c) {
return false;
}
#spanadd
});
#spanend
#spanadd
final FocusTraversalPolicy policy = new FocusTraversalPolicy() { public Component getFirstComponent(Container focusCycleRoot) { return null; } public Component getLastComponent(Container fcr) { return null; } public Component getComponentAfter(Container fcr, Component c) { return null; } public Component getComponentBefore(Container fcr, Component c) { return null; } public Component getDefaultComponent(Container fcr) { return null; } }; final FocusTraversalPolicy ftp = frame.getFocusTraversalPolicy();
- または、
TraversalKeys
を空にする
class MyGlassPane extends JPanel{ public MyGlassPane() { setOpaque(false); addKeyListener(new KeyAdapter() {}); addMouseListener(new MouseAdapter() {}); super.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); } }
#spanend
#spanadd
Set<AWTKeyStroke> s = Collections.emptySet();
#spanend
#spanadd
setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, s);
#spanend
#spanadd
setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, s);
#spanend
- &jnlp;
- &jar;
- &zip;
解説
上記のサンプルでは、カーソルを砂時計に変更し、なにもしないマウスリスナーなどを設定したGlassPaneをJFrame#setGlassPane()メソッドでフレームに追加しています。- -
Mnemonic
なども禁止したい場合は、以下のようなGlassPane
を使用する方法があります(参考: Disabling Swing Containers, the final solution?)。
#spanend
#spanadd
class LockingGlassPane extends JComponent {
#spanend
public LockingGlassPane() {
setOpaque(false);
super.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
#spandel
このため、サンプルにあるsetEnabled(true)なJTextFieldの上にマウスポインタを移動しても、処理中はカーソルアイコンは砂時計のまま変化しません。
#spanend
@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);
}
}
#spandel
//**参考リンク
#spanend
#spandel
**コメント [#h83774c4]
#spanend
-Tabキーで状態遷移しないようにするため、なにもしないFocusTraversalPolicyを追加しました。 -- [[terai]] &new{2005-04-18 (月) 10:51:25};
-2chのSwingスレが参考になります(763付近)。SwingWorkerを使う方法もあるようです。 -- [[terai]] &new{2005-04-19 (火) 17:27:58};
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frame.getGlassPane().setVisible(true);
button.setEnabled(false);
frame.setFocusTraversalPolicy(policy);
frame.getGlassPane().requestFocusInWindow();
SwingWorker worker = new SwingWorker() {
public Object construct() {
return longTask();
}
public void finished() {
frame.getGlassPane().setVisible(false);
button.setEnabled(true);
frame.setFocusTraversalPolicy(ftp);
button.requestFocusInWindow();
}
};
worker.start();
}
});
- 相当悩みました。JDialog だと同じことができないのは何でなんでしょうねぇ。。。 -- [[おれ]] &new{2006-05-17 (水) 16:33:12};
-- カーソルが変わらないのでしょうか? それともコンパイルエラーが出るとかでしょうか? -- [[terai]] &new{2006-05-17 (水) 17:59:14};
- 申し訳ない。カーソルが変わらないのだけれど、1.5系でコンパイルするとだめみたい。同じソースでも1.4系でコンパイルするとちゃんと変わる。1.5でのバグかな。。。 -- [[おれ]] &new{2006-05-18 (木) 12:58:11};
-- 追記。JDialog のコンストラクタに null を指定しているとこうなるようです。オーナフレームを指定してあげたら、1.5でもきちんと出ました。お騒がせしました。 -- [[おれ]]
-- なるほど、new JDialog((Frame)null);で試してみるとカーソルが変わらないですね。情報どうもでした。 -- [[terai]] &new{2006-05-18 (木) 21:45:15};
@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);
}
#spanadd
}
#spanend
#spanadd
- -
-
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