概要

JTableのセルエディタとしてJPanel中央に配置したJCheckBoxを設定し、そのJCheckBoxをクリックした場合のみ選択状態が変化するように設定します。

サンプルコード

class CheckBoxPanelEditor extends AbstractCellEditor implements TableCellEditor {
  private final JPanel p = new JPanel(new GridBagLayout());
  private final JCheckBox checkBox = new JCheckBox();
  public CheckBoxPanelEditor() {
    super();
    checkBox.setOpaque(false);
    checkBox.setFocusable(false);
    checkBox.setRolloverEnabled(false);
    Handler handler = new Handler();
    checkBox.addActionListener(handler);
    checkBox.addMouseListener(handler);
    p.addMouseListener(new MouseAdapter() {
      @Override public void mousePressed(MouseEvent e) {
        fireEditingStopped();
      }
    });
    p.add(checkBox);
    p.setBorder(UIManager.getBorder("Table.noFocusBorder"));
  }

  @Override public Component getTableCellEditorComponent(
      JTable table, Object value, boolean isSelected, int row, int column) {
    checkBox.setSelected(Objects.equals(value, Boolean.TRUE));
    // p.setBackground(table.getSelectionBackground());
    return p;
  }

  @Override public Object getCellEditorValue() {
    return checkBox.isSelected();
  }

  private class Handler extends MouseAdapter implements ActionListener {
    @Override public void actionPerformed(ActionEvent e) {
      fireEditingStopped();
    }

    @Override public void mousePressed(MouseEvent e) {
      Container c = SwingUtilities.getAncestorOfClass(JTable.class, e.getComponent());
      if (c instanceof JTable) {
        JTable table = (JTable) c;
        if (checkBox.getModel().isPressed()
            && table.isRowSelected(table.getEditingRow()) && e.isControlDown()) {
          p.setBackground(table.getBackground());
        } else {
          p.setBackground(table.getSelectionBackground());
        }
      }
    }

    @Override public void mouseExited(MouseEvent e) {
      Container c = SwingUtilities.getAncestorOfClass(JTable.class, e.getComponent());
      if (c instanceof JTable) {
        JTable table = (JTable) c;
        if (table.isEditing() && !table.getCellEditor().stopCellEditing()) {
          table.getCellEditor().cancelCellEditing();
        }
      }
    }
  }
}
View in GitHub: Java, Kotlin

解説

上記のサンプルでは、JTableBooleanに対応するTableCellEditorとして中央にJCheckBoxを配置したJPanelを適用しています。

  • デフォルトのJTable.BooleanEditor
    • セル全体がJCheckBoxになるためチェックアイコン以外の余白をマウスでクリックした場合でも選択状態が変化する
  • CheckBoxPanelEditor
    • JPanelの中央にJCheckBoxを配置して作成
    • 余白となるJPanel部分をクリックしてもJCheckBoxの状態は変化しない
    • JCheckBoxをマウスでクリックした場合のみその選択状態が変化する

  • 以下のようにgetTableCellEditorComponent(...)内でJPanelの背景色をセルの選択色にする場合、Ctrlキーを押しながらJCheckBoxをクリックするとセルの選択状態にズレが発生する
    • このサンプルでは、セルエディタのJCheckBoxに以下のようなマウスリスナーを追加することで回避
      class CheckBoxPanelEditor extends AbstractCellEditor implements TableCellEditor {
        private final JPanel p = new JPanel(new GridBagLayout());
        private final JCheckBox checkBox = new JCheckBox();
      
        public CheckBoxPanelEditor() {
          super();
          checkBox.setOpaque(false);
          checkBox.setFocusable(false);
          checkBox.setRolloverEnabled(false);
          checkBox.addActionListener(new ActionListener() {
            @Override public void actionPerformed(ActionEvent e) {
              fireEditingStopped();
            }
          });
          p.add(checkBox);
          p.setBorder(UIManager.getBorder("Table.noFocusBorder"));
        }
      
        @Override public Component getTableCellEditorComponent(
            JTable table, Object value, boolean isSelected, int row, int column) {
          checkBox.setSelected(Objects.equals(value, Boolean.TRUE));
          p.setBackground(table.getSelectionBackground());
          return p;
        }
      
        @Override public Object getCellEditorValue() {
          return checkBox.isSelected();
        }
      }
      

参考リンク

コメント