TITLE:Windowを開いたときのフォーカスを指定
Posted by terai at 2004-10-11

Windowを開いたときのフォーカスを指定

JFrameやJDialogなどのWindowを開いたときに、デフォルトでフォーカスを持つコンポーネントを指定します。
  • category: swing folder: DefaultFocus title: Windowを開いたときのフォーカスを指定 tags: [JFrame, JDialog, Focus, FocusTraversalPolicy, WindowListener, ComponentListener, KeyboardFocusManager] author: aterai pubdate: 2004-10-11T07:41:37+09:00 description: JFrameやJDialogなどのWindowを開いたときに、デフォルトでフォーカスを持つコンポーネントを指定します。 image: https://lh3.googleusercontent.com/_9Z4BYR88imo/TQTKp09XXEI/AAAAAAAAAWU/p3YhSijyS90/s800/DefaultFocus.png

概要

JFrameJDialogなどのWindowを開いたときに、デフォルトでフォーカスを持つコンポーネントを指定します。

#screenshot

サンプルコード

#spanend
#spanadd
* サンプルコード [#sourcecode]
#spanend
#spanadd
#code(link){{
#spanend
EventQueue.invokeLater(new Runnable() {
  public void run() {
  @Override public void run() {
    field.requestFocusInWindow();
  }
});

解説

上記のサンプルでは、JTextFieldがデフォルトのフォーカスを持つように、JComponent#requestFocusInWindowメソッドを使用しています。

解説

上記のサンプルでは、JTextFieldがデフォルトのフォーカスを持つようにJComponent#requestFocusInWindow()メソッドを使用しています。 requestFocusInWindowメソッドは、チュートリアルHow to Use the Focus Subsystemにあるように、frame.pack();した後で実行する必要があります。このため、このサンプルではEventQueue.invokeLaterを使って、待ち状態のすべてのイベントが処理されたあとで実行するようにしています。
  • JComponent#requestFocusInWindow()メソッドはチュートリアル(How to Use the Focus Subsystem)にあるようにJFrame#pack()、もしくはJFrame#setSize(...)などでリサイズされた後(フォーカスを取得するコンポーネントのサイズが決まった後)で実行する必要がある
  • このため、このサンプルではEventQueue.invokeLater(...)を使って待ち状態のすべてのイベントが処理された後で実行している

以下のように、FocusTraversalPolicyやWindowListenerを使う方法でも、同様にデフォルトのフォーカスを持つコンポーネントを指定することが出来ます。
  • 以下のようにFocusTraversalPolicyWindowListenerを使う方法でも同様にデフォルトのフォーカスを持つコンポーネントを指定可能
    • FocusTraversalPolicyを設定して最初にフォーカスの当たるコンポーネントを指定(JDK 1.4.0以降)
  • FocusTraversalPolicyを使用
    • FocusTraversalPolicy を設定して、最初にフォーカスの当たるコンポーネントを指定(JDK 1.4 以降)
      frame.setFocusTraversalPolicy(new LayoutFocusTraversalPolicy() {
        @Override
        public Component getInitialComponent(Window w) {
        @Override public Component getInitialComponent(Window w) {
          return field;
        }
      });
      
  • WindowListener#windowOpened で、requestFocusInWindow
    • フレームにWindowListenerを設定して、windowOpenedが呼び出されたときに、requestFocusInWindow
  • WindowListener#windowOpened(...)requestFocusInWindow()
    • フレームにWindowListenerを設定してwindowOpened(...)が呼び出されたときに、requestFocusInWindow()を実行
frame.addWindowListener(new WindowAdapter() {
  @Override
  public void windowOpened(WindowEvent e) {
  @Override public void windowOpened(WindowEvent e) {
    field.requestFocusInWindow();
  }
});
  • ComponentListener#componentShown で、requestFocusInWindow
    • フレームにComponentListenerを設定して、componentShownが呼び出されたとき(=フレームがsetVisible(true)されたとき)に、requestFocusInWindow
  • ComponentListener#componentShown(...)requestFocusInWindow()
    • フレームにComponentListenerを設定してcomponentShown(...)が呼び出されたとき(=フレームがsetVisible(true)されたとき)にrequestFocusInWindow()を実行
frame.addComponentListener(new ComponentAdapter() {
  @Override
  public void componentShown(ComponentEvent e) {
  @Override public void componentShown(ComponentEvent e) {
    field.requestFocusInWindow();
  }
});
  • KeyboardFocusManager#addPropertyChangeListener(...)requestFocusInWindow()
    • KeyboardFocusManagerPropertyChangeListenerを設定してpropertyChange(...)が呼び出され、PropertyNameactiveWindowかつPropertyChangeEvent#getNewValue()nullでないときにrequestFocusInWindow()を実行

参考リンク

コメント

  • JFrame#getRootPane()#setDefaultButton()は使用方法がよくわからない… -- terai
  • setDefaultButtonって、Enterしたときに押されたとみなすボタンだったかな…… --
  • なるほど、さっきやっと理解できました。JTextFieldなどを編集状態にしたあと、EnterするとsetDefaultButtonしたボタンが押されるのですね。 -- terai
  • というわけで、frame.getRootPane().setDefaultButton(eb);を追加してみました。上記のサンプルでは、中央のJTextFieldにフォーカスがある状態で、リターンキーを押すと、EASTボタンが押されたことになります。 -- terai
    • いつか、DefaultButton のページを別に作成すること。 -- terai
    • DefaultButtonの設定に移動。 -- terai
  • テスト? -- terai
    #spandel
    import java.awt.*;
    #spanend
    #spandel
    import java.awt.event.*;
    #spanend
    #spandel
    import javax.swing.*;
    #spanend
    #spandel
    class Test {
    #spanend
      public static void createAndShowGUI() {
        final JTextField textField = new JTextField("Hello");
        textField.addHierarchyListener(new HierarchyListener() {
          public void hierarchyChanged(HierarchyEvent e) {
            if((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED)!=0
                    && textField.isShowing()) {
              EventQueue.invokeLater(new Runnable(){
                public void run() {
                  textField.requestFocusInWindow();
                }
              });
            }
          }
        });
        int result = JOptionPane.showConfirmDialog(
          null, textField, "Input Text",
          JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
    #spanadd
    KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
    #spanend
    #spanadd
    kfm.addPropertyChangeListener(new PropertyChangeListener() {
    #spanend
      @Override public void propertyChange(PropertyChangeEvent e) {
        String prop = e.getPropertyName();
        if ("activeWindow".equals(prop) && e.getNewValue() != null) {
          System.out.println("activeWindow");
          field.requestFocusInWindow();
        }
      }
      public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
          public void run() {
            createAndShowGUI();
          }
        });
      }
    #spandel
    }
    #spanend
    #spanadd
    });
    #spanend
    

参考リンク

コメント