TITLE:JTableのセルにJButtonを追加して行削除
Posted by terai at 2007-10-22

JTableのセルにJButtonを追加して行削除

JTableのセルにJButtonを追加し、クリックされたらその行を削除します。主にSwing - JButton inside JTable Cellの投稿を参考にしています。
  • category: swing folder: DeleteButtonInCell title: JTableのセルにJButtonを追加して行削除 tags: [JTable, JButton, TableCellRenderer, TableCellEditor, ActionListener] author: aterai pubdate: 2007-10-22T07:55:05+09:00 description: JTableのセルにJButtonを追加し、クリックされたらその行を削除します。 image: https://lh4.googleusercontent.com/_9Z4BYR88imo/TQTKsRqqqeI/AAAAAAAAAWY/X0y-Ph7jngA/s800/DeleteButtonInCell.png

概要

JTableのセルにJButtonを追加し、クリックされたらその行を削除します。

#screenshot

サンプルコード

#spanend
#spanadd
class DeleteButton extends JButton {
#spanend
  @Override public void updateUI() {
    super.updateUI();
    setBorder(BorderFactory.createEmptyBorder());
    setFocusable(false);
    setRolloverEnabled(false);
    setText("X");
  }
#spanadd
}
#spanend

#spandel
**サンプルコード [#i9dca28f]
#spanend
#spandel
#code{{
#spanend
#spandel
class ButtonColumn extends AbstractCellEditor
#spanend
    implements TableCellRenderer, TableCellEditor {
  private static final String LABEL = "X";
  private final JButton renderButton = new JButton(LABEL);
  private final JButton editorButton;
  public ButtonColumn() {
#spanadd
class DeleteButtonRenderer extends DeleteButton implements TableCellRenderer {
#spanend
  public DeleteButtonRenderer() {
    super();
    editorButton = new JButton(new AbstractAction(LABEL) {
      public void actionPerformed(ActionEvent e) {
    setName("Table.cellRenderer");
  }
#spanadd

#spanend
  @Override public Component getTableCellRendererComponent(JTable table,
      Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    return this;
  }
#spanadd
}
#spanend
#spanadd

#spanend
#spanadd
class DeleteButtonEditor extends DeleteButton implements TableCellEditor {
#spanend
  public DeleteButtonEditor(final JTable table) {
    super();
    addActionListener(new ActionListener() {
      @Override public void actionPerformed(ActionEvent e) {
        int row = table.convertRowIndexToModel(table.getEditingRow());
        fireEditingStopped();
        ((DefaultTableModel) table.getModel()).removeRow(row);
      }
    });
    editorButton.setBorder(BorderFactory.createEmptyBorder());
    renderButton.setBorder(BorderFactory.createEmptyBorder());
    editorButton.setFocusPainted(false);
    editorButton.setRolloverEnabled(false);
    //renderButton.setToolTipText("Delete(renderButton)");
    //editorButton.setToolTipText("Delete(editorButton)");
  }
  public Component getTableCellRendererComponent(JTable table, Object value,
                      boolean isSelected, boolean hasFocus, int row, int column) {
    return renderButton;
#spanadd

#spanend
  @Override public Component getTableCellEditorComponent(JTable table,
      Object value, boolean isSelected, int row, int column) {
    return this;
  }
  public Component getTableCellEditorComponent(JTable table, Object value,
                      boolean isSelected, int row, int column) {
    return editorButton;
#spanadd

#spanend
  @Override public Object getCellEditorValue() {
    return "";
  }
  public Object getCellEditorValue() {
    return LABEL;
  }
#spanadd

#spanend
  // Copied from AbstractCellEditor
  // protected EventListenerList listenerList = new EventListenerList();
  // transient protected ChangeEvent changeEvent = null;
  // ...
}
View in GitHub: Java, Kotlin

解説

上記のサンプルでは、ボタンがクリックされたときの削除自体は、JTableに追加したマウスリスナーで行っており、セルエディタやセルレンダラーに使っているJButtonは表示のためのダミーです。
#spanend
#spandel
table.addMouseListener(new MouseAdapter() {
#spanend
  private int targetRow = -1;
  @Override public void mousePressed(MouseEvent e) {
    Point pt = e.getPoint();
    int mcol = table.convertColumnIndexToModel(table.columnAtPoint(pt));
    int vrow = table.rowAtPoint(e.getPoint());
    int mrow = (vrow>=0)?table.convertRowIndexToModel(vrow):-1;
    if(mrow>=0 && mcol==BUTTON_COLUMN) {
      targetRow = mrow;
    }
  }
  @Override public void mouseReleased(MouseEvent e) {
    Point pt = e.getPoint();
    int mcol = table.convertColumnIndexToModel(table.columnAtPoint(pt));
    int vrow = table.rowAtPoint(e.getPoint());
    int mrow = (vrow>=0)?table.convertRowIndexToModel(vrow):-1;
    if(targetRow==mrow && mcol==BUTTON_COLUMN) {
      model.removeRow(mrow);
    }
    targetRow = -1;
  }
#spandel
});
#spanend
#spandel

解説

  • セルレンダラーに使用するJButtonは表示専用でクリックイベントなどは無視される
  • セルエディタとして使用するJButtonActionListenerを追加し、このJButtonがクリックされたらAbstractCellEditorからコピーしたfireEditingStopped()メソッドでセルの編集を終了し、TableModelから対象行を削除
    • セルレンダラー、セルエディタがコンポーネント(もしくはDefaultCellEditor)を継承していないとJTableLookAndFeelを変更てもセルレンダラー、セルエディタのupdateUI()が呼ばれない
      • JTable#updateUI()Java 1.6.0JTable#updateSubComponentUI(...)Java 1.7.0SwingUtilities#updateRendererOrEditorUI(Object)を参照
    • AbstractCellEditorを継承していてもupdateUI()は呼ばれない、DefaultCellEditorは継承しづらい…
複数選択を許可しない場合は、Swing - JButton inside JTable Cellのように、セルエディタにリスナーを追加し、選択されたセルを削除する方法もあります。
#spanend
#spandel
public ButtonColumn(final JTable table) {
#spanend
  super();
  table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
  editorButton = new JButton(new AbstractAction(LABEL) {
    public void actionPerformed(ActionEvent e) {
      fireEditingStopped();
      int row = table.convertRowIndexToModel(table.getSelectedRow());
      ((DefaultTableModel)table.getModel()).removeRow(row);
    }
  });
  //...
#spandel
複数選択を許可する場合は、Ctrlキーなどを押しながらのボタンクリックに注意する必要があります。

参考リンク

参考リンク

コメント