JTableのソートをキー入力で実行する
Total: 38
, Today: 3
, Yesterday: 35
Posted by aterai at
Last-modified:
Summary
JTable
やJTableHeader
にフォーカスが存在する場合、マウスクリックではなくキー入力でソート可能になるよう設定します。
Screenshot
Advertisement
Source Code Examples
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;
}
View in GitHub: Java, KotlinExplanation
JTableHeader
にフォーカスが存在する場合SPACEキーでtoggleSortOrder
アクションが実行されてソートが可能だが、方向指定したソートは不可能JTable
にフォーカスが存在する場合は、F8キーでfocusHeader
アクションを実行してJTableHeader
にフォーカス移動してからtoggleSortOrder
アクションを実行する必要がある
JTable
とJTableHeader
のActionMap
、InputMap
にそれぞれ以下のソートAction
とKeyStroke
を追加ascendant
アクション、ctrl+↑キー(KeyStroke.getKeyStroke("ctrl UP")
)descendant
アクション、ctrl+↓キー(KeyStroke.getKeyStroke("ctrl DOWN")
)unsorted
アクション、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
で使用不可能)
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;
}
}