TITLE:JTableのセルにJButtonを追加して行削除
#navi(../)
RIGHT:Posted by [[aterai]] at 2007-10-22
*JTableのセルにJButtonを追加して行削除 [#y5a20522]
JTableのセルにJButtonを追加し、クリックされたらその行を削除します。主に[http://forums.sun.com/thread.jspa?threadID=680674 Swing - JButton inside JTable Cell]の投稿を参考にしています。

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

//#screenshot
#ref(http://lh4.ggpht.com/_9Z4BYR88imo/TQTKsRqqqeI/AAAAAAAAAWY/X0y-Ph7jngA/s800/DeleteButtonInCell.png)

**サンプルコード [#i9dca28f]
#code{{
class ButtonColumn extends AbstractCellEditor
    implements TableCellRenderer, TableCellEditor {
  private static final String LABEL = "X";
  private final JButton renderButton = new JButton(LABEL);
  private final JButton editorButton;
  public ButtonColumn() {
    super();
    editorButton = new JButton(new AbstractAction(LABEL) {
      public void actionPerformed(ActionEvent e) {
        fireEditingStopped();
      }
    });
    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;
  }
  public Component getTableCellEditorComponent(JTable table, Object value,
                      boolean isSelected, int row, int column) {
    return editorButton;
  }
  public Object getCellEditorValue() {
    return LABEL;
  }
}
}}

**解説 [#qcbd9c4d]
上記のサンプルでは、ボタンがクリックされたときの削除自体は、JTableに追加したマウスリスナーで行っており、セルエディタやセルレンダラーに使っているJButtonは表示のためのダミーです。
#code{{
table.addMouseListener(new MouseAdapter() {
  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;
  }
});
}}

複数選択を許可しない場合は、[http://forums.sun.com/thread.jspa?threadID=680674 Swing - JButton inside JTable Cell]のように、セルエディタにリスナーを追加し、選択されたセルを削除する方法もあります。
#code{{
public ButtonColumn(final JTable table) {
  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);
    }
  });
  //...
}}
複数選択を許可する場合は、Ctrlキーなどを押しながらのボタンクリックに注意する必要があります。

**参考リンク [#kcf3a9d4]
-[http://forums.sun.com/thread.jspa?threadID=680674 Swing - JButton inside JTable Cell]
-[[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/view_bug.do?bug_id=6291631 Bug ID: 6291631 JTable: rowAtPoint returns 0 for negative y] -- [[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