• 追加された行はこの色です。
  • 削除された行はこの色です。
---
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
---
* 概要 [#summary]
`JTable`のセルに`JButton`を追加し、クリックされたらその行を削除します。

#download(https://lh4.googleusercontent.com/_9Z4BYR88imo/TQTKsRqqqeI/AAAAAAAAAWY/X0y-Ph7jngA/s800/DeleteButtonInCell.png)

* サンプルコード [#sourcecode]
#code(link){{
class DeleteButton extends JButton {
  @Override public void updateUI() {
    super.updateUI();
    setBorder(BorderFactory.createEmptyBorder());
    setFocusable(false);
    setRolloverEnabled(false);
    setText("X");
  }
}

class DeleteButtonRenderer extends DeleteButton implements TableCellRenderer {
  public DeleteButtonRenderer() {
    super();
    setName("Table.cellRenderer");
  }

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

class DeleteButtonEditor extends DeleteButton implements TableCellEditor {
  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);
      }
    });
  }

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

  @Override public Object getCellEditorValue() {
    return "";
  }
  //Copied from AbstractCellEditor
  //protected EventListenerList listenerList = new EventListenerList();
  //transient protected ChangeEvent changeEvent = null;
//......

  // Copied from AbstractCellEditor
  // protected EventListenerList listenerList = new EventListenerList();
  // transient protected ChangeEvent changeEvent = null;
  // ...
}
}}

* 解説 [#explanation]
%%上記のサンプルでは、ボタンがクリックされたときの削除自体は、`JTable`に追加したマウスリスナーで行っており、セルエディタやセルレンダラーに使っている`JButton`は表示のためのダミーです。%%

- セルレンダラーに使っている`JButton`は表示のためのダミー
- セルエディタとして使用する`JButton`に`ActionListener`を追加し、この`JButton`がクリックされたら`AbstractCellEditor`からコピーした`fireEditingStopped()`メソッドでセルの編集を終了し、`TableModel`から行を削除
-- セルレンダラー、セルエディタがコンポーネント(もしくは`DefaultCellEditor`)を継承していないと、`JTable`の`LookAndFeel`を変更てもセルレンダラー、セルエディタの`updateUI()`が呼ばれない
- セルレンダラーに使用する`JButton`は表示専用でクリックイベントなどは無視される
- セルエディタとして使用する`JButton`に`ActionListener`を追加し、この`JButton`がクリックされたら`AbstractCellEditor`からコピーした`fireEditingStopped()`メソッドでセルの編集を終了し、`TableModel`から対象行を削除
-- セルレンダラー、セルエディタがコンポーネント(もしくは`DefaultCellEditor`)を継承していないと`JTable`の`LookAndFeel`を変更てもセルレンダラー、セルエディタの`updateUI()`が呼ばれない
--- `JTable#updateUI()`、`Java 1.6.0`の`JTable#updateSubComponentUI(...)`、`Java 1.7.0`の`SwingUtilities#updateRendererOrEditorUI(Object)`を参照
-- `AbstractCellEditor`を継承していても`updateUI()`は呼ばれない、`DefaultCellEditor`は継承しづらい…

* 参考リンク [#reference]
- [https://community.oracle.com/thread/1357728 Swing - JButton inside JTable Cell]
- [[JTableの行を追加、削除>Swing/AddRow]]
- [[JTableの行を全削除>Swing/ClearTable]]
- [[JTableのセルに複数のJButtonを配置する>Swing/MultipleButtonsInTableCell]]
- [[JTableのセルにHyperlinkを表示>Swing/HyperlinkInTableCell]]

* コメント [#comment]
#comment
- ボタンのセル内でマウスを移動しても削除するように変更。 -- &user(aterai); &new{2008-03-28 (金) 16:59:11};
-- メモ: %%`0`行目のボタンをクリックし、真上のヘッダ上でリリースしても削除可能%% 修正済み: [http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6291631 Bug ID: 6291631 JTable: rowAtPoint returns 0 for negative y] (追記: このバグは未修正になっているけど、`JDK 1.6, 1.7`などのソースではコメントにある修正が追加されている) -- &user(aterai); &new{2008-03-28 (金) 17:21:10};
-- メモ: %%`0`行目のボタンをクリックし、真上のヘッダ上でリリースしても削除可能%% 修正済み: [https://bugs.openjdk.org/browse/JDK-6291631 Bug ID: 6291631 JTable: rowAtPoint returns 0 for negative y] (追記: このバグは未修正になっているけど、`JDK 1.6, 1.7`などのソースではコメントにある修正が追加されている) -- &user(aterai); &new{2008-03-28 (金) 17:21:10};

#code{{
//上記のBug Databaseにある回避方法
JTable table = new JTable(model) {
  @Override public int rowAtPoint(Point pt) {
    return (pt.y < 0) ? -1 : super.rowAtPoint(pt);
  }
};
}}

- テスト -- &user(aterai); &new{2009-09-27 (日) 01:34:58};
-- [[JTableのセルに複数のJButtonを配置する>Swing/MultipleButtonsInTableCell]]に移動。 -- &user(aterai); &new{2009-10-05 (日) 01:34:58};

#comment