概要

JLabelを継承するヘッダのTableCellRendererHTMLフォーマットのinputタグで生成したcheckboxを表示し、クリックに応じてその状態を変更します。

サンプルコード

class HeaderRenderer implements TableCellRenderer {
  private static String INPUT = "<html><table cellpadding='0' cellspacing='0'>"
                              + "<td><input type='checkbox'><td>&nbsp;Check All";
  @Override public Component getTableCellRendererComponent(
      JTable table, Object value, boolean isSelected, boolean hasFocus,
      int row, int column) {
    TableCellRenderer r = table.getTableHeader().getDefaultRenderer();
    Component c = r.getTableCellRendererComponent(
        table, INPUT, isSelected, hasFocus, row, column);
    if (c instanceof JLabel) {
      for (Component cmp : ((JLabel) c).getComponents()) {
        updateCheckBox(((Container) cmp).getComponent(0), value);
      }
    }
    return c;
  }

  private static void updateCheckBox(Component c, Object value) {
    if (c instanceof JCheckBox) {
      JCheckBox check = (JCheckBox) c;
      check.setOpaque(false);
      check.setBorder(BorderFactory.createEmptyBorder());
      // check.setText("Check All");
      if (value instanceof Status) {
        switch ((Status) value) {
        case SELECTED:
          check.setSelected(true);
          check.setEnabled(true);
          break;
        case DESELECTED:
          check.setSelected(false);
          check.setEnabled(true);
          break;
        case INDETERMINATE:
          check.setSelected(true);
          check.setEnabled(false);
          break;
        default:
          throw new AssertionError("Unknown Status");
        }
      }
    }
  }
}
View in GitHub: Java, Kotlin

解説

  • NimbusLookAndFeelJTableHeaderにJCheckBoxを追加してセルの値を切り替えるのようにJCheckBoxをアイコン化してこれをヘッダセルレンダラーにJLabel#setIcon(...)を使用して設定すると、ソートアイコンの設定と干渉(ソートを使用しない場合でも)して意図した表示にならない場合がある
  • そのためサンプルでは、アイコン化したJCheckBoxではなくHTMLフォーマットの<input type='checkbox'>タグをJLabel#setText(...)メソッドで設定してチェックボックスを表示
  • <input>要素のchecked属性を使用して選択状態のJCheckBoxを表示可能だが、disabled属性で無効状態にできない
  • 代わりにHTMLコンポーネントのレンダリングを行うコンポーネントをJLabelから取得し、その子要素からJCheckBox自体を取得して直接JCheckBox#setEnabled(...)JCheckBox#setSelected(...)メソッドで状態を変更
  • Java 11以降で実行するとヘッダのチェックボックス描画が更新されない場合がある?
    • 調査中
    • Java 8では問題なし

参考リンク

コメント