• title: JTableのセル内部にあるJCheckBoxのみクリック可能に設定する tags: [JTable, JCheckBox, TableCellEditor, JPanel] author: aterai pubdate: 2015-07-20T03:20:06+09:00 description: JTableのセル内部に配置したJCheckBoxをクリックした場合だけ、そのJCheckBoxの選択状態が変化するように可能に設定します。

概要

JTableのセル内部に配置した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

解説

上記のサンプルでは、JTableのBooleanに対応する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();
  }
}

参考リンク

コメント