• 追加された行はこの色です。
  • 削除された行はこの色です。
TITLE:Windowを開いたときのフォーカスを指定
#navi(../)
*Windowを開いたときのフォーカスを指定 [#q0754f35]
Posted by [[terai]] at 2004-10-11
---
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
---
* 概要 [#summary]
`JFrame`や`JDialog`などの`Window`を開いたときに、デフォルトでフォーカスを持つコンポーネントを指定します。

#contents
#download(https://lh3.googleusercontent.com/_9Z4BYR88imo/TQTKp09XXEI/AAAAAAAAAWU/p3YhSijyS90/s800/DefaultFocus.png)

**概要 [#ead3df11]
JFrameやJDialogなどのWindowを開いたときに、デフォルトでフォーカスを持つコンポーネントを指定します。
* サンプルコード [#sourcecode]
#code(link){{
EventQueue.invokeLater(new Runnable() {
  @Override public void run() {
    field.requestFocusInWindow();
  }
});
}}

-&jnlp;
-&jar;
-&zip;
* 解説 [#explanation]
上記のサンプルでは、`JTextField`がデフォルトのフォーカスを持つように`JComponent#requestFocusInWindow()`メソッドを使用しています。

#screenshot
- `JComponent#requestFocusInWindow()`メソッドはチュートリアル([https://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html How to Use the Focus Subsystem])にあるように`JFrame#pack()`、もしくは`JFrame#setSize(...)`などでリサイズされた後(フォーカスを取得するコンポーネントのサイズが決まった後)で実行する必要がある
- このため、このサンプルでは`EventQueue.invokeLater(...)`を使って待ち状態のすべてのイベントが処理された後で実行している

**サンプルコード [#c961d3aa]
----
- 以下のように`FocusTraversalPolicy`や`WindowListener`を使う方法でも同様にデフォルトのフォーカスを持つコンポーネントを指定可能
-- `FocusTraversalPolicy`を設定して最初にフォーカスの当たるコンポーネントを指定(`JDK 1.4.0`以降)

#code{{
frame.getRootPane().setDefaultButton(eb);
EventQueue.invokeLater(new Runnable() {
  public void run() {
frame.setFocusTraversalPolicy(new LayoutFocusTraversalPolicy() {
  @Override public Component getInitialComponent(Window w) {
    return field;
  }
});
}}

- `WindowListener#windowOpened(...)`で`requestFocusInWindow()`
-- フレームに`WindowListener`を設定して`windowOpened(...)`が呼び出されたときに、`requestFocusInWindow()`を実行

#code{{
frame.addWindowListener(new WindowAdapter() {
  @Override public void windowOpened(WindowEvent e) {
    field.requestFocusInWindow();
  }
});
}}

**解説 [#u7271535]
サンプルでは、JTextFieldがデフォルトのフォーカスを持つように、JComponent#requestFocusInWindowメソッドを使用しています。
- `ComponentListener#componentShown(...)`で`requestFocusInWindow()`
-- フレームに`ComponentListener`を設定して`componentShown(...)`が呼び出されたとき(=フレームが`setVisible(true)`されたとき)に`requestFocusInWindow()`を実行

----
requestFocusInWindowメソッドは、チュートリアル[[How to Use the Focus Subsystem>http://java.sun.com/docs/books/tutorial/uiswing/misc/focus.html]]にあるように、frame.pack();した後で実行します。このため、このサンプルではEventQueue.invokeLaterを使って、待ち状態のすべてのイベントが処理されたあとで実行するようにしています。
#code{{
frame.addComponentListener(new ComponentAdapter() {
  @Override public void componentShown(ComponentEvent e) {
    field.requestFocusInWindow();
  }
});
}}

----
JDK 1.4 以降なら、FocusTraversalPolicy を設定して、最初にフォーカスの当たるコンポーネントを指定する方法もあります。
- `KeyboardFocusManager#addPropertyChangeListener(...)`で`requestFocusInWindow()`
-- `KeyboardFocusManager`に`PropertyChangeListener`を設定して`propertyChange(...)`が呼び出され、`PropertyName`が`activeWindow`かつ`PropertyChangeEvent#getNewValue()`が`null`でないときに`requestFocusInWindow()`を実行

#code{{
frame.setFocusTraversalPolicy(new DefaultFocusTraversalPolicy() {
  @Override
  public Component getFirstComponent(Container focusCycleRoot) {
    return field;
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
kfm.addPropertyChangeListener(new PropertyChangeListener() {
  @Override public void propertyChange(PropertyChangeEvent e) {
    String prop = e.getPropertyName();
    if ("activeWindow".equals(prop) && e.getNewValue() != null) {
      System.out.println("activeWindow");
      field.requestFocusInWindow();
    }
  }
  //getDefaultComponentのデフォルト実装はgetFirstComponentをラップ
  //@Override
  //public Component getDefaultComponent(Container aContainer) {
  //  return field; //getFirstComponent(aContainer);
  //}
  //getInitialComponentのデフォルト実装はgetDefaultComponentを使用
  //@Override
  //public Component getInitialComponent(Window w) {
  //  return field;
  //}
});
}}

**参考リンク [#z4f652d0]
-[[Focusの移動>Swing/FocusTraversal]]
* 参考リンク [#reference]
- [[Focusの移動>Swing/FocusTraversal]]
- [https://community.oracle.com/thread/1367389 Swing - When does requestFocusInWindow() fail]
- [[JOptionPaneのデフォルトフォーカス>Swing/OptionPaneDefaultFocus]]

**コメント [#x1950fff]
-JFrame#getRootPane()#setDefaultButton()は使用方法がよくわからない… -- [[terai]] 
-setDefaultButtonって、Enterしたときに押されたとみなすボタンだったかな…… --  &new{2004-10-14 (木) 23:21:53};
-なるほど、さっきやっと理解できました。JTextFieldなどを編集状態にしたあと、EnterするとsetDefaultButtonしたボタンが押されるのですね。 -- [[terai]] &new{2004-10-18 (月) 12:14:15};
-というわけで、frame.getRootPane().setDefaultButton(eb);を追加してみました。上記のサンプルでは、中央のJTextFieldにフォーカスがある状態で、リターンキーを押すと、EASTボタンが押されたことになります。 -- [[terai]] &new{2004-10-18 (月) 12:20:58};
* コメント [#comment]
#comment
- `JFrame#getRootPane()#setDefaultButton()`は使用方法がよくわからない… -- [[aterai]]
- `setDefaultButton`って、KBD{Enter}したときに押されたとみなすボタンだったかな…… --  &new{2004-10-14 (木) 23:21:53};
-- ありがとうございます。おかげでようやく理解できました。`JTextField`などにフォーカスがある状態でKBD{Enter}キーを入力すると`setDefaultButton`したボタンが押されるのですね。 -- &user(aterai); &new{2004-10-18 (月) 12:14:15};
-- というわけで、`frame.getRootPane().setDefaultButton(eb);`を追加してみました。上記のサンプルでは、中央の`JTextField`にフォーカスがある状態で、KBD{Enter}キーを押すと、`EAST`ボタンが押されたことになります。 -- &user(aterai); &new{2004-10-18 (月) 12:20:58};
-- %%いつか、`DefaultButton`のページを別に作成すること。 -- &user(aterai); &new{2008-05-07 (水) 19:19:44};%%
-- [[DefaultButtonの設定>Swing/DefaultButton]]に移動。 -- &user(aterai); &new{2008-05-12 (月) 14:40:15};
- `HierarchyListener`を使用する場合のテスト -- &user(aterai); &new{2009-03-19 (木) 14:51:30};
-- [[JOptionPaneのデフォルトフォーカス>Swing/OptionPaneDefaultFocus]]に移動

#comment