Swing/MultipleButtonsInTableCell のバックアップの現在との差分(No.3)
TITLE:JTableのセルに複数のJButtonを配置する
Posted by terai at 2009-10-05
JTableのセルに複数のJButtonを配置する
JTableのセル内にクリック可能な複数のJButtonを配置します。-
category: swing
folder: MultipleButtonsInTableCell
title: JTableのセルに複数のJButtonを配置する
tags: [JTable, TableCellEditor, TableCellRenderer, JButton, JPanel, ActionListener]
author: aterai
pubdate: 2009-10-05T12:57:02+09:00
description: JTableのセル内にクリック可能な複数のJButtonを配置します。
image:
hreflang:
href: https://java-swing-tips.blogspot.com/2009/10/multiple-jbuttons-in-jtable-cell.html lang: en
概要
JTable
のセル内にクリック可能な複数のJButton
を配置します。
- &jnlp;
- &jar;
- &zip;
Screenshot
Advertisement
#screenshot
サンプルコード
#spanend
#spanadd
class ButtonsPanel extends JPanel {
#spanend
public final List<JButton> buttons =
Arrays.asList(new JButton("view"), new JButton("edit"));
public ButtonsPanel() {
super();
setOpaque(true);
for (JButton b: buttons) {
b.setFocusable(false);
b.setRolloverEnabled(false);
add(b);
}
}
#spanadd
}
#spanend
#spandel
**サンプルコード [#ybe99159]
#spanend
#spandel
#code{{
#spanend
#spandel
class ButtonsEditorRenderer extends AbstractCellEditor
#spanend
implements TableCellRenderer,TableCellEditor{
private final JPanel renderer = new JPanel();
private final JPanel editor = new JPanel();
public ButtonsEditorRenderer(final JTable table) {
#spanadd
class ButtonsRenderer extends ButtonsPanel
#spanend
implements TableCellRenderer {
public ButtonsRenderer() {
super();
JButton viewButton2 = new JButton(new AbstractAction("view2") {;
@Override
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) {
Color bgc = isSelected ? table.getSelectionBackground()
: table.getBackground()
setBackground(bgc);
return this;
}
#spanadd
}
#spanend
#spanadd
#spanend
#spanadd
class ButtonsEditor extends ButtonsPanel
#spanend
implements TableCellEditor {
public ButtonsEditor(final JTable table) {
super();
// ---->
// DEBUG: view button click
// -> control key down + edit button(same cell) press
// -> remain selection color
MouseListener ml = new MouseAdapter() {
@Override public void mousePressed(MouseEvent e) {
ButtonModel m = ((JButton) e.getSource()).getModel();
if (m.isPressed() && table.isRowSelected(table.getEditingRow())
&& e.isControlDown()) {
setBackground(table.getBackground());
}
}
};
buttons.get(0).addMouseListener(ml);
buttons.get(1).addMouseListener(ml);
// <----
#spanadd
#spanend
buttons.get(0).addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
fireEditingStopped();
JOptionPane.showMessageDialog(table, "Viewing");
}
});
JButton editButton2 = new JButton(new AbstractAction("edit2") {;
@Override
public void actionPerformed(ActionEvent e) {
//int row = table.convertRowIndexToModel(table.getSelectedRow());
int row = table.getSelectedRow();
#spanadd
#spanend
buttons.get(1).addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
int row = table.convertRowIndexToModel(table.getEditingRow());
Object o = table.getModel().getValueAt(row, 0);
JOptionPane.showMessageDialog(table, "Editing: "+o);
fireEditingStopped();
JOptionPane.showMessageDialog(table, "Editing: " + o);
}
});
renderer.setOpaque(true);
renderer.add(new JButton("view1"));
renderer.add(new JButton("edit1"));
editor.setOpaque(true);
editor.add(viewButton2);
editor.add(editButton2);
#spanadd
#spanend
addMouseListener(new MouseAdapter() {
@Override public void mousePressed(MouseEvent e) {
fireEditingStopped();
}
});
}
@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;
#spanadd
#spanend
@Override public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
this.setBackground(table.getSelectionBackground());
return this;
}
@Override
public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column) {
editor.setBackground(table.getSelectionBackground());
return editor;
}
@Override
public Object getCellEditorValue() {
#spanadd
#spanend
@Override public Object getCellEditorValue() {
return "";
}
#spandel
}
#spanend
#spanadd
#spanend
// Copied from AbstractCellEditor
// protected EventListenerList listenerList = new EventListenerList();
transient protected ChangeEvent changeEvent = null;
@Override public boolean isCellEditable(java.util.EventObject e) {
return true;
}
#spanadd
// ...
#spanend
View in GitHub: Java, Kotlin解説
上記のサンプルでは、CellRenderer用とCellEditor用に、JButtonを2つ配置したJPanelをそれぞれ作成しています。アクションイベントを設定するのは、CellEditor用のJButtonで、CellRenderer用のJButtonは表示のためのダミーです。解説
上記のサンプルでは、CellRenderer
用とCellEditor
用にJButton
を2
つ配置したJPanel
をそれぞれ作成しています。CellRenderer
用のJButton
は表示のみに使用するため、クリック後に実行するAction
はCellEditor
用のJButton
だけに設定しています。
行の選択状態が切り替わるとき(例えば、一行目を選択していて、二行目のボタンをクリック)には、CellEditor用のJButtonがうまくクリックできないので、JTable自体に以下のようなマウスリスナーを設定しています。
-
LookAndFeel
などが更新されたらJTable#updateUI()
メソッド内でSwingUtilities#updateRendererOrEditorUI()
メソッドを呼び出すなどして各セルレンダラーやセルエディタ(これらはJTable
の子コンポーネントではないので)を更新-
AbstractCellEditor
を継承するセルエディタはComponent
もDefaultCellEditor
も継承していないのでLookAndFeel
を変更しても追従しない - そのため
JTable#updateUI()
をオーバーライドしてセルエディタ自体を再作成するなどの対応が必要
-
- このサンプルでは、
Component
を継承(TableCellEditor
を実装)するセルエディタを作成し、AbstractCellEditor
から必要なメソッドをコピーして回避している
#spandel
class CellButtonsMouseListener extends MouseAdapter{
#spanend
private Component component = null;
private boolean isOnButtonColumn(MouseEvent e) {
JTable t = (JTable)e.getComponent();
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;
#spanadd
// SwingUtilities#updateRendererOrEditorUI()
#spanend
#spanadd
static void updateRendererOrEditorUI(Object rendererOrEditor) {
#spanend
if (rendererOrEditor == null) {
return;
}
private Component getCellComponentAt(MouseEvent e) {
JTable t = (JTable)e.getComponent();
Point p = e.getPoint();
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);
Component component = null;
if (rendererOrEditor instanceof Component) {
component = (Component) rendererOrEditor;
}
@Override
public void mousePressed(MouseEvent e) {
if(isOnButtonColumn(e)) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JTable t = (JTable)e.getComponent();
Point pt = e.getPoint();
component = getCellComponentAt(e);
component.requestFocusInWindow();
t.editCellAt(t.rowAtPoint(pt), t.columnAtPoint(pt));
}
});
}
if (rendererOrEditor instanceof DefaultCellEditor) {
component = ((DefaultCellEditor) rendererOrEditor).getComponent();
}
@Override
public void mouseReleased(MouseEvent e) {
if(isOnButtonColumn(e)) {
Component c = getCellComponentAt(e);
if(c instanceof JButton && c==component) ((JButton)c).doClick();
component = null;
}
if (component != null) {
SwingUtilities.updateComponentTreeUI(component);
}
}
- -
-
JSpinner
(2
つのJButton
とJTextField
の組み合わせ)をCellEditor
に使用する
参考リンク
参考リンク
- JTableのセルにJButtonを追加して行削除
- JTableのセルにHyperlinkを表示
- Table Button Column « Java Tips Weblog
- JTableのセル中にJRadioButtonを配置
- JTableのCellにJCheckBoxを複数配置する
- [JDK-8138667] java.lang.IllegalAccessError: tried to access method (for a protected method) - Java Bug System
-
Java 8
でEventQueue.invokeLater( () -> fireEditingStopped() );
ではなくEventQueue.invokeLater(ButtonsEditor.this::fireEditingStopped);
のようなコードを実行するとIllegalAccessError
になる場合がある -
Java 9
で修正済
-
コメント
- 第0列目が編集状態でボタンをクリックした場合、パネルが二度表示されるバグを修正。 -- terai
コメント
- 第
0
列目が編集状態でボタンをクリックした場合、パネルが2
度表示されるバグを修正。 -- aterai - Table Button Column « Java Tips Weblogを参考にして、
JTable#editCellAt
ではなく、逆にTableCellEditor#stopCellEditing()
を使用してクリック直後に編集終了するように変更。 -- aterai - Ctrlキーを押しながら、
edit
ボタンをクリックすると異なる行(table.getSelectedRow()
)の内容が表示されるバグを修正。 -- aterai - すごいと思いました! -- いわく
- こんばんは。たしかに
JTable
のTableCellRenderer
、TableCellEditor
の仕組みは、すごい良くできているといつも感心してしまいます :) -- aterai
- こんばんは。たしかに