---
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 static void columnSort(ActionEvent e, SortOrder order) {
Object o = e.getSource();
if (o instanceof JTable) {
JTable table = (JTable) o;
JTableHeader header = table.getTableHeader();
if (header != null) {
table.getActionMap().get("focusHeader").actionPerformed(e);
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;
JTable table = header.getTable();
int col = getSelectedColumnIndex(header);
sort(table, col, order);
}
}
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;
}
}}
* Description [#explanation]
* Description [#description]
- `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()`で取得した列でソートし、その後`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