TITLE:JTableのセルにJButtonを追加して行削除
#navi(../)
#tags(JTable, JButton, TableCellRenderer, TableCellEditor, ActionListener)
RIGHT:Posted by &author(aterai); at 2007-10-22
* JTableのセルにJButtonを追加して行削除 [#y5a20522]
``JTable``のセルに``JButton``を追加し、クリックされたらその行を削除します。

- &jnlp;
- &jar;
- &zip;

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

** サンプルコード [#i9dca28f]
#code(link){{
class DeleteButton extends JButton {
  @Override public void updateUI() {
    super.updateUI();
    setBorder(BorderFactory.createEmptyBorder());
    setFocusable(false);
    setRolloverEnabled(false);
    setText("X");
  }
}
}}
#code{{
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;
  }
}
}}
#code{{
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 "";
  }
  //Copid from AbstractCellEditor
  //protected EventListenerList listenerList = new EventListenerList();
  //transient protected ChangeEvent changeEvent = null;
//......
}}

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

- セルレンダラーに使っている``JButton``は表示のためのダミー
- セルエディタとして使用する``JButton``に``ActionListener``を追加し、クリックされたら``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``は継承しづらい…

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

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

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

#comment