---
category: swing
folder: CheckBoxCellEditor
title: JTableのセル内部にあるJCheckBoxのみクリック可能にする
tags: [JTable, JCheckBox, TableCellEditor, JPanel]
author: aterai
pubdate: 2015-07-20T03:24:10+09:00
description: JTableのセルエディタとしてJPanel中央に配置したJCheckBoxを設定し、そのJCheckBoxをクリックした場合のみ選択状態が変化するように設定します。
image: https://lh3.googleusercontent.com/-t1TDt_cSOzU/VavlaZDRBaI/AAAAAAAAN9c/nVCdYcC71e8/s800-Ic42/CheckBoxCellEditor.png
---
* 概要 [#summary]
`JTable`のセルエディタとして`JPanel`中央に配置した`JCheckBox`を設定し、その`JCheckBox`をクリックした場合のみ選択状態が変化するように設定します。

#download(https://lh3.googleusercontent.com/-t1TDt_cSOzU/VavlaZDRBaI/AAAAAAAAN9c/nVCdYcC71e8/s800-Ic42/CheckBoxCellEditor.png)

* サンプルコード [#sourcecode]
#code(link){{
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());
    // 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();
        }
      }
    }
  }
}
}}

* 解説 [#explanation]
上記のサンプルでは、`JTable`の`Boolean`に対応する`TableCellEditor`として、中央に`JCheckBox`を配置した`JPanel`を適用しています。

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

----
- 以下のように`getTableCellEditorComponent(...)`内で`JPanel`の背景色をセルの選択色にする場合、KBD{Ctrl}キーを押しながら`JCheckBox`をクリックするとセルの選択状態にズレが発生する
-- このサンプルでは、セルエディタの`JCheckBox`に以下のようなマウスリスナーを追加することで回避
#code{{
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();
  }
}
}}

* 参考リンク [#reference]
- [[JTableのCellにJCheckBoxを複数配置する>Swing/CheckBoxesInTableCell]]
- [[JCheckBoxのセルをロールオーバーする>Swing/RolloverBooleanRenderer]]

* コメント [#comment]
#comment
#comment