Swing/DeleteButtonInCell のバックアップの現在との差分(No.10)
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:
概要
JTable
のセルにJButton
を追加し、クリックされたらその行を削除します。
- &jnlp;
- &jar;
- &zip;
Screenshot
Advertisement
#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
は表示専用でクリックイベントなどは無視される - セルエディタとして使用する
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
は継承しづらい…
- セルレンダラー、セルエディタがコンポーネント(もしくは
#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キーなどを押しながらのボタンクリックに注意する必要があります。
参考リンク
- Swing - JButton inside JTable Cell
- JTableの行を追加、削除
- JTableの行を全削除
- JTableのセルに複数のJButtonを配置する
- JTableのセルにHyperlinkを表示
参考リンク
コメント
- ボタンのセル内でマウスを移動しても削除するように変更。 -- aterai
- メモ:
修正済み: Bug ID: 6291631 JTable: rowAtPoint returns 0 for negative y (追記: このバグは未修正になっているけど、0
行目のボタンをクリックし、真上のヘッダ上でリリースしても削除可能JDK 1.6, 1.7
などのソースではコメントにある修正が追加されている) -- aterai
- メモ:
コメント
- ボタンのセル内でマウスを移動しても削除するように変更。 -- terai
- メモ: 0行目のボタンをクリックし、真上のヘッダ上でリリースしても削除できる -> Bug ID: 6291631 JTable: rowAtPoint returns 0 for negative y -- terai
//上記のBug Databaseにある回避方法 JTable table = new JTable(model) { @Override public int rowAtPoint(Point pt) { return (pt.y<0)?-1:super.rowAtPoint(pt); return (pt.y < 0) ? -1 : super.rowAtPoint(pt); } };
- メモ: 0行目のボタンをクリックし、真上のヘッダ上でリリースしても削除できる -> Bug ID: 6291631 JTable: rowAtPoint returns 0 for negative y -- terai
- テスト -- terai
#spanend #spandel import java.awt.*; #spanend #spandel import java.awt.event.*; #spanend #spandel import java.util.EventObject; #spanend #spandel import javax.swing.*; #spanend #spandel import javax.swing.table.*; #spanend #spandel public class MultipleButtonsInCellTest2 { #spanend JTable t; public JComponent makeUI() { String[] columnNames = {"String", "Button"}; Object[][] data = { {"AAA", null}, {"BBB", null} }; DefaultTableModel model = new DefaultTableModel(data, columnNames) { @Override public Class<?> getColumnClass(int column) { return getValueAt(0, column).getClass(); } }; t = new JTable(model); t.addMouseListener(new MouseAdapter() { private boolean isOnButtonColumn(MouseEvent e) { Point pt = e.getPoint(); int mcol = t.convertColumnIndexToModel(t.columnAtPoint(pt)); int vrow = t.rowAtPoint(pt); int mrow = (vrow>=0)?t.convertRowIndexToModel(vrow):-1; return mrow>=0 && mcol==1; } private Component getCellComponentAt(Point p) { int row = t.rowAtPoint(p); int col = t.columnAtPoint(p); TableCellEditor ce = t.getCellEditor(row,col); Component c = ce.getTableCellEditorComponent(t,null,true,row,col); Point pt = SwingUtilities.convertPoint(t, p, c); return SwingUtilities.getDeepestComponentAt(c, pt.x, pt.y); } @Override public void mousePressed(MouseEvent e) { if(isOnButtonColumn(e)) { Point pt = e.getPoint(); component = getCellComponentAt(pt); t.editCellAt(t.rowAtPoint(pt), t.columnAtPoint(pt)); } } @Override public void mouseReleased(MouseEvent e) { if(isOnButtonColumn(e)) { Component c = getCellComponentAt(e.getPoint()); if(c instanceof JButton && c==component) ((JButton)c).doClick(); component = null; } } Component component = null; }); t.setRowHeight(36); ActionPanelEditorRenderer er = new ActionPanelEditorRenderer(); TableColumn column = t.getColumnModel().getColumn(1); column.setCellRenderer(er); column.setCellEditor(er); JPanel p = new JPanel(new BorderLayout()); p.add(new JScrollPane(t)); p.setPreferredSize(new Dimension(320, 200)); return p; } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { createAndShowGUI(); } }); } public static void createAndShowGUI() { JFrame f = new JFrame(); f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); f.getContentPane().add(new MultipleButtonsInCellTest2().makeUI()); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); } #spandel } #spanend #spandel class ActionPanelEditorRenderer extends AbstractCellEditor #spanend implements TableCellRenderer,TableCellEditor{ JPanel renderer = new JPanel(); JPanel editor = new JPanel(); public ActionPanelEditorRenderer() { super(); JButton viewButton2 = new JButton(new AbstractAction("view2") {; public void actionPerformed(ActionEvent e) { JOptionPane.showMessageDialog(null, "Viewing"); } }); JButton editButton2 = new JButton(new AbstractAction("edit2") {; public void actionPerformed(ActionEvent e) { JOptionPane.showMessageDialog(null, "Editing"); } }); renderer.setOpaque(true); renderer.add(new JButton("view1")); renderer.add(new JButton("edit1")); editor.setOpaque(true); editor.add(viewButton2); editor.add(editButton2); } @Override public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { renderer.setBackground(isSelected?table.getSelectionBackground() :table.getBackground()); return renderer; } @Override public Component getTableCellEditorComponent( JTable table, Object value, boolean isSelected, int row, int column) { editor.setBackground(table.getSelectionBackground()); return editor; } @Override public Object getCellEditorValue() { return null; } #spandel } #spanend #spandel
- テスト -- aterai
- JTableのセルに複数のJButtonを配置するに移動。 -- aterai