ボタンのフォーカス遷移を循環させる

意外に簡単に出来てしまったので、逆に忘れないようにメモ。


Windowsでは上のようにパネルなどのダイアログやパネル等のコンテナの上にボタンが複数載っている構成では、上下左右の矢印キーでボタンのフォーカスをサイクルできるようになっている。(通常の遷移キーとしてTabキーが用意されているにも関わらず矢印キーを未だに有効にしている経緯は不明だが)当然ながらSwingのダイアログではデフォルトではそのような振る舞いは実装されていないので、自分で用意しなくてはならない。

がしかし、これは比較的簡単に実現できる。

  • フォーカス遷移のキーストロークを追加する

フォーカス遷移を前進させるキー(↓→)と後退させるキー(↑←)を現在のボタンのフォーカス遷移キーのセットに追加する。(同一コンテナ上に配置する全てのボタンに行う)

final int forward = KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS;
final int backward = KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS;
JButton yesButton = new JButton("はい(Y)");

//前進キーのセットに下、右矢印キーを追加
HashSet forwardKeySet = new HashSet();
forwardKeySet.addAll(yesButton.getFocusTraversalKeys(forward));
forwardKeySet.add(KeyStroke.getAWTKeyStroke(KeyEvent.VK_DOWN, 0));
forwardKeySet.add(KeyStroke.getAWTKeyStroke(KeyEvent.VK_RIGHT, 0));
yesButton.setFocusTraversalKeys(forward, forwardKeySet);

//後退キーのセットに上、左矢印キーを追加
HashSet backwardKeySet = new HashSet();
backwardKeySet.addAll(yesButton.getFocusTraversalKeys(backward));
backwardKeySet.add(KeyStroke.getAWTKeyStroke(KeyEvent.VK_UP, 0));
backwardKeySet.add(KeyStroke.getAWTKeyStroke(KeyEvent.VK_LEFT, 0));
yesButton.setFocusTraversalKeys(backward, backwardKeySet);

ちょっと冗長なのが気に食わないが、他の方法は知らないのだ(もっと良い方法があれば、誰か教えてほしい)

  • コンテナのフォーカス遷移基点を有効にする

Swingのコンテナとなることができるコンポーネント(java.awt.Container)クラスは、フォーカス遷移の基点となるためのプロパティ(focusCycleRoot)があるため、フォーカス遷移を循環させるグループをまとめたコンテナ上でこれを有効にする必要がある。

JPanel containerPane = new JPanel();
JButton yesButton = new JButton("はい(Y)");
JButton noButton = new JButton("いいえ(N)");
containerPane.add(yesButton);
containerPane.add(noButton);
containerPane.setFocusCycleRoot(true);

この操作が無いと矢印キーによりコンテナ上の端のボタンから更にフォーカスを遷移させた際に他にコンテナがある場合は循環せず、次のコンテナ上のコンポーネントにフォーカスが移動してしまう。

以上の二通りの実装を施すことでフォーカス遷移を矢印で循環させることができる。