JTableHeaderにJCheckBoxを追加してセルの値を切り替える
Total: 16484, Today: 1, Yesterday: 1
Posted by aterai at
Last-modified:
Summary
JTableHeaderにJCheckBoxを追加して、同じ列のJCheckBoxで表示している値をすべて切り替えます。
Screenshot

Advertisement
Source Code Examples
class HeaderRenderer implements TableCellRenderer {
private final JCheckBox check = new JCheckBox("");
private final JLabel label = new JLabel("Check All");
@Override public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
if (value instanceof Status) {
((Status) value).configureHeaderCheckBox(check);
} else {
Status.INDETERMINATE.configureHeaderCheckBox(check);
}
check.setOpaque(false);
check.setFont(table.getFont());
TableCellRenderer r = table.getTableHeader().getDefaultRenderer();
Component c = r.getTableCellRendererComponent(
table, value, isSelected, hasFocus, row, column);
if (c instanceof JLabel) {
JLabel l = (JLabel) c;
label.setIcon(new ComponentIcon(check));
l.setIcon(new ComponentIcon(label));
l.setText(null); // XXX: Nimbus???
}
return c;
}
}
enum Status {
SELECTED {
@Override void configureHeaderCheckBox(JCheckBox check) {
check.setSelected(true);
check.setEnabled(true);
}
},
DESELECTED {
@Override void configureHeaderCheckBox(JCheckBox check) {
check.setSelected(false);
check.setEnabled(true);
}
},
INDETERMINATE {
@Override void configureHeaderCheckBox(JCheckBox check) {
check.setSelected(true);
check.setEnabled(false);
}
};
abstract void configureHeaderCheckBox(JCheckBox check);
}
class ComponentIcon implements Icon {
private final JComponent cmp;
public ComponentIcon(JComponent cmp) {
this.cmp = cmp;
}
@Override public int getIconWidth() {
return cmp.getPreferredSize().width;
}
@Override public int getIconHeight() {
return cmp.getPreferredSize().height;
}
@Override public void paintIcon(Component c, Graphics g, int x, int y) {
SwingUtilities.paintComponent(
g, cmp, c.getParent(), x, y, getIconWidth(), getIconHeight());
}
}
View in GitHub: Java, KotlinDescription
上記のサンプルでは、JCheckBoxのアイコンを作成し、これをTableCellRenderer(=JLabel)にsetIcon(...)メソッドで設定しています。
JCheckBoxをアイコン化しているので、これをクリックしてもイベントは発生しない- 代わりにヘッダ自体に
MouseListenerを追加し、マウスクリックイベントが発生するとアイコンの入れ替えることでチェック状態の表示を更新する
- 代わりにヘッダ自体に
LookAndFeelによってはTableCellRendererのソートアイコンと競合する場合がある
JTableのモデルの更新JTableのセル中にあるJCheckBoxが全てチェックされた場合、ヘッダのJCheckBoxもチェックされるJTableのセル中にあるJCheckBoxのチェックが全てクリアされた場合、ヘッダのJCheckBoxのチェックもクリアされるJTableのセル中にあるJCheckBoxでチェックの有無が混在している場合、ヘッダのJCheckBoxは薄くチェックされた状態(setEnabled(false)でsetSelected(true))になる
このサンプルでは行の追加、削除を考慮していない- 行の追加、削除に対応したサンプルは、JTableのモデルが変更されたことをイベントで受け取るに移動
- このサンプルでは、以下のようなメソッドで毎回行のチェック状態を確認する方法に変更
private Status resolveHeaderState(TableModel model) {
Status status = null;
int rowCount = model.getRowCount();
if (rowCount > 0) {
List<Boolean> values = IntStream.range(0, rowCount)
.mapToObj(i -> Objects.equals(model.getValueAt(i, targetColumnIndex), true))
.distinct()
.limit(2)
.collect(Collectors.toList()); // Java 16: .toList();
boolean repaintHeader = values.size() == 1;
if (repaintHeader) {
boolean isSelected = values.get(0); // Java 21: .getFirst();
status = isSelected ? Status.SELECTED : Status.DESELECTED;
}
}
return status;
}
Reference
- Check Box in JTable header (Swing / AWT / SWT / JFace forum at JavaRanch)
- JCheckBoxに不定状態のアイコンを追加する
- JTableのモデルが変更されたことをイベントで受け取る