• category: swing folder: CellEditorFocusCycle title: JTableのセルエディタ内でタブキーによるフォーカス移動を有効にする tags: [JTable, TableCellEditor, Focus, FocusTraversalPolicy] author: aterai pubdate: 2019-03-25T17:24:54+09:00 description: JTableが編集中の場合はセルエディタ内でタブキーによるフォーカス移動が可能になるよう設定します。 image: https://drive.google.com/uc?id=1m3-6T_FyHa51fARDyoZ92MJKfAVox1HjjQ hreflang:
       href: https://java-swing-tips.blogspot.com/2019/07/enable-focus-move-by-tab-key-in-cell.html
       lang: en

概要

JTableが編集中の場合はセルエディタ内でタブキーによるフォーカス移動が可能になるよう設定します。

サンプルコード

JTable table = makeTable();
ActionMap am = table.getActionMap();
Action sncc = am.get("selectNextColumnCell");
Action action = new AbstractAction() {
  @Override public void actionPerformed(ActionEvent e) {
    if (!table.isEditing() || !isEditorFocusCycle(table.getEditorComponent())) {
      // System.out.println("Exit editor");
      sncc.actionPerformed(e);
    }
  }
};
am.put("selectNextColumnCell2", action);

InputMap im = table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), "selectNextColumnCell2");
// ...
protected boolean isEditorFocusCycle(Component editor) {
  Component child = CheckBoxesEditor.getEditorFocusCycleAfter(editor);
  if (child != null) {
    child.requestFocus();
    return true;
  }
  return false;
}
// ...
public static Component getEditorFocusCycleAfter(Component editor) {
  Component fo = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
  if (fo == null || !(editor instanceof Container)) {
    return null;
  }
  Container root = (Container) editor;
  if (!root.isFocusCycleRoot()) {
    root = root.getFocusCycleRootAncestor();
  }
  if (root == null) {
    return null;
  }
  // System.out.println("FocusCycleRoot: " + root.getClass().getName());
  FocusTraversalPolicy ftp = root.getFocusTraversalPolicy();
  Component child = ftp.getComponentAfter(root, fo);
  if (child != null && SwingUtilities.isDescendingFrom(child, editor)) {
    // System.out.println("requestFocus: " + child.getClass().getName());
    // child.requestFocus();
    return child;
  }
  return null;
}
View in GitHub: Java, Kotlin

解説

  • 上: デフォルトのJTable
    • KeyEvent.VK_TABにはselectNextColumnCellアクションが割り当てられており、このアクションはtable.getCellEditor().stopCellEditing()メソッドで編集を中断して次のセルを選択する
  • 下: selectNextColumnCellアクションを置換
    • セルエディタが複数の子コンポーネントを持つFocusCycleRootコンポーネントであり、そのセルが編集中の場合はFocusTraversalPolicyを取得してセル内でフォーカス移動、編集中でない場合はselectNextColumnCellアクションを実行するアクションを作成して、KeyEvent.VK_TABに割り当てる
    • このサンプルではShift+Tabでの逆順フォーカス移動には対応していないので、編集が中断されて前のセルにフォーカスが移動する

参考リンク

コメント