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

Posted by terai at 2004-10-11

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

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

  • &jnlp;
  • &jar;
  • &zip;

#screenshot

サンプルコード

EventQueue.invokeLater(new Runnable() {
  public void run() {
    field.requestFocusInWindow();
  }
});

解説

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

requestFocusInWindowメソッドは、チュートリアルHow to Use the Focus Subsystemにあるように、frame.pack();した後で実行する必要があります。このため、このサンプルではEventQueue.invokeLaterを使って、待ち状態のすべてのイベントが処理されたあとで実行するようにしています。


以下のように、FocusTraversalPolicyやWindowListenerを使う方法でも、同様にデフォルトのフォーカスを持つコンポーネントを指定することが出来ます。

  • FocusTraversalPolicyを使用
    • FocusTraversalPolicy を設定して、最初にフォーカスの当たるコンポーネントを指定(JDK 1.4 以降)
      frame.setFocusTraversalPolicy(new LayoutFocusTraversalPolicy() {
        @Override
        public Component getInitialComponent(Window w) {
          return field;
        }
      });
      
  • WindowListener#windowOpened で、requestFocusInWindow
    • フレームにWindowListenerを設定して、windowOpenedが呼び出されたときに、requestFocusInWindow
      frame.addWindowListener(new WindowAdapter() {
        @Override
        public void windowOpened(WindowEvent e) {
          field.requestFocusInWindow();
        }
      });
      
  • ComponentListener#componentShown で、requestFocusInWindow
    • フレームにComponentListenerを設定して、componentShownが呼び出されたとき(=フレームがsetVisible(true)されたとき)に、requestFocusInWindow
      frame.addComponentListener(new ComponentAdapter() {
        @Override
        public void componentShown(ComponentEvent e) {
          field.requestFocusInWindow();
        }
      });
      
  • KeyboardFocusManager#addPropertyChangeListener で、requestFocusInWindow
    • KeyboardFocusManagerにPropertyChangeListenerを設定して、propertyChangeが呼び出され、PropertyNameが、"activeWindow"、かつPropertyChangeEvent#getNewValueがnullでないときに、requestFocusInWindow
      KeyboardFocusManager focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
      focusManager.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
        public void propertyChange(java.beans.PropertyChangeEvent e) {
          String prop = e.getPropertyName();
          if("activeWindow".equals(prop) && e.getNewValue()!=null) {
            System.out.println("activeWindow");
            field.requestFocusInWindow();
          }
        }
      });
      

参考リンク

コメント

  • JFrame#getRootPane()#setDefaultButton()は使用方法がよくわからない… -- terai
  • setDefaultButtonって、Enterしたときに押されたとみなすボタンだったかな…… --
    • ありがとうございます。おかげでようやく理解できました。JTextFieldなどを編集状態にしたあと、EnterするとsetDefaultButtonしたボタンが押されるのですね。 -- terai
    • というわけで、frame.getRootPane().setDefaultButton(eb);を追加してみました。上記のサンプルでは、中央のJTextFieldにフォーカスがある状態で、リターンキーを押すと、EASTボタンが押されたことになります。 -- terai
    • いつか、DefaultButton のページを別に作成すること。 -- terai
    • DefaultButtonの設定に移動。 -- terai
  • HierarchyListenerを使用する場合のテスト -- terai
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    class Test {
      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);
      }
      public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
          public void run() {
            createAndShowGUI();
          }
        });
      }
    }