概要

ComponentFocus移動を親Containerに追加した順番で循環するContainerOrderFocusTraversalPolicyを設定します。

サンプルコード

JPanel p = new JPanel(new GridBagLayout());
p.setFocusTraversalPolicy(new ContainerOrderFocusTraversalPolicy());
p.setFocusTraversalPolicyProvider(true);
p.setFocusable(false);
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridx = 1;
List<JComponent> list = Arrays.asList(
    new JRadioButton("JRadioButton1"),
    new JRadioButton("JRadioButton2"),
    new JRadioButton("JRadioButton3", true),
    new JLabel("JLabel1"),
    new JLabel("JLabel2"),
    new JCheckBox("JCheckBox1"),
    new JCheckBox("JCheckBox2"));
for (JComponent c : list) {
  if (c instanceof JRadioButton) {
    group.add((JRadioButton) c);
  } else if (c instanceof JLabel) {
    c.setFocusable(false);
  }
  p.add(c, gbc);
}
gbc.gridx = 2;
gbc.weightx = 1.0;
list.forEach(c -> p.add(new JTextField(), gbc));
View in GitHub: Java, Kotlin

解説

  • LayoutFocusTraversalPolicy
    • Swingの軽量コンポーネントのデフォルト
      • ContainerOrderFocusTraversalPolicyを継承するDefaultFocusTraversalPolicyAWTの重量コンポーネント用のデフォルト
      • DefaultFocusTraversalPolicy#accept(...)をオーバーライドして軽量コンポーネントは拒否するので、JPanelなどの軽量コンポーネントにDefaultFocusTraversalPolicyを設定するとタブキーによる子コンポーネントのフォーカス移動が不可になる
    • 追加順ではなくレイアウトされた座標などに従って(SortingFocusTraversalPolicyLayoutComparatorを参照)フォーカス移動するため、たとえばこのサンプルのJRadioButtonの次のフォーカスは右隣のJTextFieldになる
  • ContainerOrderFocusTraversalPolicy
    • コンポーネントの追加順(Container#getComponentZOrder(...)で取得可能なZ軸順インデックス)でフォーカス移動するFocusTraversalPolicy
    • たとえばこのサンプルのJRadioButtonの次のフォーカスはJCheckBoxになる
      • タブキーによるフォーカス移動でJRadioButtonの次がJRadioButtonにならないのは、同一ButtonGroup内のボタンはスキップするようBasicButtonUIで設定されているため
      • LayoutFocusTraversalPolicyではJLabelのようなJComponent.WHEN_FOCUSED時のInputMapが存在しないコンポーネントは自動的にフォーカス移動対象外となるが、ContainerOrderFocusTraversalPolicyはそうではないので、このサンプルのJLabelにはsetFocusable(false)を設定することでフォーカス移動の対象から除外している
  • ContainerOrderFocusTraversalPolicy + ButtonGroupFocusTraversalPolicy

参考リンク

コメント