Swing/TableSortActionMap の変更点
- 追加された行はこの色です。
- 削除された行はこの色です。
- Swing/TableSortActionMap へ行く。
- Swing/TableSortActionMap の差分を削除
--- category: swing folder: TableSortActionMap title: JTableのソートをキー入力で実行する tags: [JTable, JTableHeader, TableRowSorter, ActionMap, InputMap] author: aterai pubdate: 2025-01-20T02:05:16+09:00 description: JTableやJTableHeaderにフォーカスが存在する場合、マウスクリックではなくキー入力でソート可能になるよう設定します。 image: https://drive.google.com/uc?id=1kqcmLvCkScEmE0J8tuGG14Kasonb3XOZ --- * Summary [#summary] `JTable`や`JTableHeader`にフォーカスが存在する場合、マウスクリックではなくキー入力でソート可能になるよう設定します。 #download(https://drive.google.com/uc?id=1kqcmLvCkScEmE0J8tuGG14Kasonb3XOZ) * Source Code Examples [#sourcecode] #code(link){{ private void initMap(JTable table, String key, String ks, SortOrder order) { Action a = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { columnSort(e, order); } }; table.getActionMap().put(key, a); InputMap im1 = table.getInputMap(WHEN_FOCUSED); im1.put(KeyStroke.getKeyStroke(ks), key); JTableHeader header = table.getTableHeader(); header.getActionMap().put(key, a); InputMap im2 = header.getInputMap(WHEN_FOCUSED); im2.put(KeyStroke.getKeyStroke(ks), key); } private void columnSort(ActionEvent e, SortOrder order) { JTable table = null; int col = -1; private static void columnSort(ActionEvent e, SortOrder order) { Object o = e.getSource(); if (o instanceof JTable) { table = (JTable) o; JTable table = (JTable) o; JTableHeader header = table.getTableHeader(); if (header != null) { table.getActionMap().get("focusHeader").actionPerformed(e); col = table.getSelectedColumn(); int col = table.getSelectedColumn(); sort(table, col, order); int id = ActionEvent.ACTION_PERFORMED; String cmd = "focusTable"; ActionEvent ae = new ActionEvent(header, id, cmd); header.getActionMap().get(cmd).actionPerformed(ae); } } else if (o instanceof JTableHeader) { JTableHeader header = (JTableHeader) o; table = header.getTable(); col = getSelectedColumnIndex(header); JTable table = header.getTable(); int col = getSelectedColumnIndex(header); sort(table, col, order); } if (col >= 0 && table != null) { } private static void sort(JTable table, int col, SortOrder order) { if (col >= 0) { RowSorter.SortKey sortKey = new RowSorter.SortKey(col, order); table.getRowSorter().setSortKeys(Collections.singletonList(sortKey)); } } private int getSelectedColumnIndex(JTableHeader header) { int col = -1; TableColumnModel cm = header.getColumnModel(); for (int i = 0; i < cm.getColumnCount(); i++) { TableCellRenderer r = cm.getColumn(i).getHeaderRenderer(); if (r instanceof ColumnHeaderRenderer) { col = ((ColumnHeaderRenderer) r).getSelectedColumnIndex(); if (col >= 0) { break; } } } return col; } }} * Explanation [#explanation] - `JTableHeader`にフォーカスが存在する場合KBD{SPACE}キーで`toggleSortOrder`アクションが実行されてソートが可能だが、方向指定したソートは不可能 -- `JTable`にフォーカスが存在する場合は、KBD{F8}キーで`focusHeader`アクションを実行して`JTableHeader`にフォーカス移動してから`toggleSortOrder`アクションを実行する必要がある - `JTable`と`JTableHeader`の`ActionMap`、`InputMap`にそれぞれ以下のソート`Action`と`KeyStroke`を追加 -- `ascendant`アクション、KBD{ctrl+↑}キー(`KeyStroke.getKeyStroke("ctrl UP")`) -- `descendant`アクション、KBD{ctrl+↓}キー(`KeyStroke.getKeyStroke("ctrl DOWN")`) -- `unsorted`アクション、KBD{F9}キー(`KeyStroke.getKeyStroke("F9")`) - ソート`Action`はソート方向を保持し`JTable`、`JTableHeader`のどちらでイベントが実行されたかを判断してソートを実行する -- `JTable`にフォーカスが存在する状態の場合、`focusHeader`アクションを実行して`JTableHeader`にフォーカス移動してから`JTable#getSelectedColumn()`で取得した列でソート -- `JTable`にフォーカスが存在する状態の場合、`focusHeader`アクションを実行して`JTableHeader`にフォーカス移動してから`JTable#getSelectedColumn()`で取得した列でソートし、その後`JTableHeader`から`focusTable`アクションを取得、実行して`JTable`にフォーカスを戻す -- `JTableHeader`にフォーカスが存在する状態の場合、現在選択されている列を取得する必要があるが`BasicTableHeaderUI#getSelectedColumnIndex()`メソッドは`private`で使用不可能のため、フォーカスが存在する`TableColumn`のインデックスを保持するだけの`TableCellRenderer`を`TableColumn#setHeaderRenderer(...)`ですべての列に設定 --- `TableCellRenderer#getTableCellRendererComponent(...)`以下のようにフォーカスが存在する場合の列インデックスを保持する(選択状態`isSelected`は列選択モデルでは常に`-1`で使用不可能) #code{{ class ColumnHeaderRenderer implements TableCellRenderer { private int selectedIndex = -1; @Override public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { if (hasFocus) { selectedIndex = column; } TableCellRenderer r = table.getTableHeader().getDefaultRenderer(); return r.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, column); } public int getSelectedColumnIndex() { return selectedIndex; } } }} * Reference [#reference] - [[JTableがデフォルトでソートする列を設定する>Swing/DefaultSortingColumn]] * Comment [#comment] #comment #comment