TITLE:Cursorを砂時計に変更

Cursorを砂時計に変更

編集者:Terai Atsuhiro~

作成日:2004-06-07
更新日:2024-02-05 (月) 15:47:59
  • category: swing folder: WaitCursor title: Cursorを砂時計に変更 tags: [Cursor, GlassPane, FocusTraversalPolicy, SwingWorker] author: aterai pubdate: 2004-06-07T13:57:16+09:00 description: バックグラウンドで処理が実行されている間は、Cursorに砂時計が設定されたGlassPaneを有効にします。 image: https://lh5.googleusercontent.com/_9Z4BYR88imo/TQTWfYWDbsI/AAAAAAAAApU/rldJwQuVm-8/s800/WaitCursor.png

概要

バックグラウンドで処理が実行されている間は、Cursorに砂時計が設定されたGlassPaneを有効にします。

概要

処理中、マウスカーソルを砂時計に変更します。

#screenshot

サンプルコード

#spanend
#spandel
frame.setGlassPane(new MyGlassPane());
#spanend
#spanadd
* サンプルコード [#sourcecode]
#spanend
#spanadd
#code(link){{
#spanend
#spanadd
frame.setGlassPane(new LockingGlassPane());
#spanend
frame.getGlassPane().setVisible(false);
button.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent e) {
  @Override public void actionPerformed(ActionEvent e) {
    frame.getGlassPane().setVisible(true);
    button.setEnabled(false);
    Thread t = new Thread(new Runnable() {
      public void run() {
        longTask();
        EventQueue.invokeLater(new Runnable() {
          public void run() {
            frame.getGlassPane().setVisible(false);
            button.setEnabled(true);
          }
        });
    new SwingWorker() {
      @Override public Object doInBackground() {
        doSomeLongTask();
        return "Done";
      }
    });
    //t.setPriority(Thread.MIN_PRIORITY);
    t.start();
#spanadd

#spanend
      @Override public void done() {
        frame.getGlassPane().setVisible(false);
        button.setEnabled(true);
      }
    }.execute();
  }
});
#spandel

#spanend
#spandel
class MyGlassPane extends JComponent {
#spanend
  public MyGlassPane() {
#spanadd
// ...
#spanend
#spanadd
class LockingGlassPane extends JComponent {
#spanend
  public LockingGlassPane() {
    setOpaque(false);
    setFocusTraversalPolicy(new DefaultFocusTraversalPolicy() {
      public boolean accept(Component c) {return false;}
      @Override public boolean accept(Component c) {
        return false;
      }
    });
    addKeyListener(new KeyAdapter() {});
    addMouseListener(new MouseAdapter() {});
    requestFocusInWindow();
    super.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
  }
  public void setVisible(boolean flag) {
#spanadd

#spanend
  @Override public void setVisible(boolean flag) {
    super.setVisible(flag);
    setFocusTraversalPolicyProvider(flag);
  }
}
  • &jnlp;
  • &jar;
  • &zip;

解説

上記のサンプルでは、カーソルを砂時計に変更し、なにもしないマウスリスナーなどを設定したGlassPaneをJFrame#setGlassPane()メソッドでフレームに追加しています。

解説

上記のサンプルでは、カーソルを砂時計に変更し、なにもしないマウスリスナーなどを設定したGlassPaneJFrame#setGlassPane()メソッドでフレームに追加しています。 スタートボタンがクリックされて処理が継続している間は、このGlassPaneが有効になり、マウス、キー、フォーカス移動などのイベントが、すべてGlassPaneに奪われるため、フレーム内のコンポーネントをアクセス不可にすることが出来ます。 スタートボタンがクリックされて処理が継続している間はこのGlassPaneが有効になり、マウス、キー入力、フォーカス移動などのイベントがすべてGlassPaneに奪われるため、フレーム内のコンポーネントがアクセス不可状態になります。 このため、サンプルにあるsetEnabled(true)なJTextFieldの上にマウスポインタを移動しても、処理中はカーソルアイコンは砂時計のまま変化しません。 このため、サンプルにあるsetEnabled(true)JTextFieldの上にマウスポインタを移動しても処理中はカーソルアイコンは砂時計のまま変化しません。

コメント

  • Tabキーで状態遷移しないようにするため、なにもしないFocusTraversalPolicyを追加しました。 -- terai
  • 2chのSwingスレが参考になります(763付近)。SwingWorkerを使う方法もあるようです。 -- terai
    • - Tabキーなどによるフォーカス移動を禁止する場合は、GlassPaneに以下のような設定を行います。
  • どのコンポーネントにもフォーカス移動できないFocusTraversalPolicyを設定する
#spandel
button.addActionListener(new ActionListener() {
#spanend
  public void actionPerformed(ActionEvent e) {
    frame.getGlassPane().setVisible(true);
    button.setEnabled(false);
    frame.getGlassPane().requestFocusInWindow();
    SwingWorker worker = new SwingWorker() {
      public Object construct() {
        return longTask();
      }
      public void finished() {
        frame.getGlassPane().setVisible(false);
        button.setEnabled(true);
        button.requestFocusInWindow(); 
      }
    };
    worker.start();
#spanadd
setFocusTraversalPolicy(new DefaultFocusTraversalPolicy() {
#spanend
  @Override public boolean accept(Component c) {
    return false;
  }
});
  • 相当悩みました。JDialog だと同じことができないのは何でなんでしょうねぇ。。。 -- おれ
    • カーソルが変わらないのでしょうか? それともコンパイルエラーが出るとかでしょうか? -- terai
  • 申し訳ない。カーソルが変わらないのだけれど、1.5系でコンパイルするとだめみたい。同じソースでも1.4系でコンパイルするとちゃんと変わる。1.5でのバグかな。。。 -- おれ
    • 追記。JDialog のコンストラクタに null を指定しているとこうなるようです。オーナフレームを指定してあげたら、1.5でもきちんと出ました。お騒がせしました。 -- おれ
    • なるほど、new JDialog((Frame)null);で試してみるとカーソルが変わらないですね。情報どうもでした。 -- terai
  • DefaultFocusTraversalPolicy を使うように変更しました。 -- terai
#spanend
#spanadd
Set<AWTKeyStroke> s = Collections.emptySet();
#spanend
#spanadd
setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, s);
#spanend
#spanadd
setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, s);
#spanend
#spanadd
#spanend
#spanadd
class LockingGlassPane extends JComponent {
#spanend
  public LockingGlassPane() {
    setOpaque(false);
    super.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
  }
#spanadd

#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);
    }
  }
#spanadd

#spanend
  @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キーを押すとメニューバーにフォーカスが移動する場合がある
  • -

参考リンク

コメント