Swing/CheckBoxesInTableCell のバックアップの現在との差分(No.2)
TITLE:JTableのCellにJCheckBoxを複数配置する
Posted by aterai at 2011-02-28
JTableのCellにJCheckBoxを複数配置する
JTableのセル中にJCheckBoxを複数個配置します。-
category: swing
folder: CheckBoxesInTableCell
title: JTableのCellにJCheckBoxを複数配置する
tags: [JTable, JCheckBox, TableCellRenderer, TableCellEditor, JPanel, InputMap, ActionMap]
author: aterai
pubdate: 2011-02-28T15:07:56+09:00
description: JTableのセル中にJCheckBoxを複数個配置します。
image:
hreflang:
href: https://java-swing-tips.blogspot.com/2011/03/checkboxes-in-jtable-cell.html lang: en
概要
JTable
のセル中にJCheckBox
を複数個配置します。
- &jnlp;
- &jar;
- &zip;
Screenshot
Advertisement
サンプルコード
#spanend
#spandel
class CheckBoxEditorRenderer extends AbstractCellEditor
#spanend
implements TableCellRenderer, TableCellEditor {
#spanadd
* サンプルコード [#sourcecode]
#spanend
#spanadd
#code(link){{
#spanend
#spanadd
class CheckBoxesPanel extends JPanel {
#spanend
private static final String OSNAME = System.getProperty("os.name");
protected final String[] title = {"r", "w", "x"};
protected final CheckBoxPanel editor = new CheckBoxPanel(title);
protected final CheckBoxPanel renderer = new CheckBoxPanel(title);
protected void updateButtons(CheckBoxPanel p, Object v) {
Integer i = (Integer)(v==null?0:v);
p.buttons[0].setSelected((i&(1<<2))!=0);
p.buttons[1].setSelected((i&(1<<1))!=0);
p.buttons[2].setSelected((i&(1<<0))!=0);
public JCheckBox[] buttons;
public CheckBoxesPanel() {
super();
setOpaque(false);
setBackground(new Color(0x0, true));
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
initButtons();
}
@Override public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row, int col) {
updateButtons(renderer, value);
return renderer;
#spanadd
#spanend
protected void initButtons() {
buttons = new JCheckBox[title.length];
for (int i = 0; i < buttons.length; i++) {
JCheckBox b = new JCheckBox(title[i]);
b.setOpaque(false);
b.setFocusable(false);
b.setRolloverEnabled(false);
b.setBackground(new Color(0x0, true));
buttons[i] = b;
add(b);
add(Box.createHorizontalStrut(5));
}
}
@Override public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
updateButtons(editor, value);
return editor;
}
@Override public Object getCellEditorValue() {
int i = 0;
if(editor.buttons[0].isSelected()) i|=1<<2;
if(editor.buttons[1].isSelected()) i|=1<<1;
if(editor.buttons[2].isSelected()) i|=1<<0;
return i;
}
#spandel
}
#spanend
#spandel
解説
上記のサンプルでは、JTableのCell内に3つのJCheckBoxを配置したJPanelを作成し、これをCellRendererとCellEditorとして別々に使用しています。JCheckBoxをマウスでクリックすると、そのJCheckBoxの選択状態だけが変化します(注: キーボードからの入力には対応していません)。- - ヘッダカラムの移動、リサイズ(JFrameなどのリサイズ)で、チェックした内容が消えてしまわないように、JTable自体に以下の様なMouseListenerを追加してチェックボックスがクリックされるたびにtable.getCellEditor(row, col).stopCellEditing();を呼び出しています。
#spanend
#spandel
table.addMouseListener(new MouseAdapter() {
#spanend
@Override public void mouseReleased(MouseEvent e) {
JTable t = (JTable)e.getComponent();
Point p = e.getPoint();
int row = t.rowAtPoint(p);
int col = t.columnAtPoint(p);
if(t.convertColumnIndexToModel(col)==1) {
t.getCellEditor(row, col).stopCellEditing();
protected void updateButtons(Object v) {
if ("Windows 7".equals(OSNAME)) { //Windows aero?
removeAll();
initButtons();
}
Integer i = (Integer) (v == null ? 0 : v);
buttons[0].setSelected((i & (1 << 2)) != 0);
buttons[1].setSelected((i & (1 << 1)) != 0);
buttons[2].setSelected((i & (1 << 0)) != 0);
}
#spandel
});
#spanend
#spandel
}
JTableにではなく、CellEditor自体にMouseListenerを追加する方法もあります。
#spanend
#spandel
class CheckBoxEditorRenderer2 extends CheckBoxEditorRenderer
#spanend
implements MouseListener {
private final JTable table;
public CheckBoxEditorRenderer2(JTable table) {
#spanadd
class CheckBoxesRenderer extends CheckBoxesPanel
#spanend
implements TableCellRenderer, Serializable {
public CheckBoxesRenderer() {
super();
this.table = table;
editor.addMouseListener(this);
setName("Table.cellRenderer");
}
//Copied form http://tips4java.wordpress.com/2009/07/12/table-button-column/
private boolean isButtonColumnEditor;
@Override public void mousePressed(MouseEvent e) {
if(table.isEditing() && table.getCellEditor() == this) {
isButtonColumnEditor = true;
}
#spanadd
#spanend
@Override public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row, int column) {
updateButtons(value);
return this;
}
@Override public void mouseReleased(MouseEvent e) {
if(isButtonColumnEditor && table.isEditing()) {
table.getCellEditor().stopCellEditing();
}
isButtonColumnEditor = false;
}
@Override public void mouseClicked(MouseEvent e) {}
@Override public void mouseEntered(MouseEvent e) {}
@Override public void mouseExited(MouseEvent e) {}
#spanadd
#spanend
public static class UIResource extends CheckBoxesRenderer implements UIResource {}
}
#spandel
参考リンク
コメント
- EnumSetのテスト -- aterai
#spanend #spandel import java.awt.*; #spanend #spandel import java.awt.event.*; #spanend #spandel import java.util.*; #spanend #spandel import javax.swing.*; #spanend #spandel import javax.swing.table.*; #spanend #spandel public class EnumSetTest { #spanend public JComponent makeUI() { String[] columnNames = { "rwx", "user" }; Object[][] data = { {"read", EnumSet.of(User.OWNER)}, {"write", EnumSet.of(User.OWNER, User.GROUP)}, {"execute", EnumSet.of(User.OWNER, User.GROUP, User.OTHER)} }; DefaultTableModel model = new DefaultTableModel(data, columnNames) { @Override public Class<?> getColumnClass(int column) { return getValueAt(0, column).getClass(); #spanadd class CheckBoxesEditor extends CheckBoxesPanel #spanend implements TableCellEditor, Serializable { public CheckBoxesEditor() { ActionListener al = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { fireEditingStopped(); } }; JTable table = new JTable(model); table.addMouseListener(new MouseAdapter() { @Override public void mouseReleased(MouseEvent e) { JTable t = (JTable)e.getComponent(); Point p = e.getPoint(); int row = t.rowAtPoint(p); int col = t.columnAtPoint(p); if (t.convertColumnIndexToModel(col)==1) { t.getCellEditor(row, col).stopCellEditing(); ActionMap am = getActionMap(); for (int i = 0; i < buttons.length; i++) { final JCheckBox b = buttons[i]; b.addActionListener(al); am.put(title[i], new AbstractAction(title[i]) { @Override public void actionPerformed(ActionEvent e) { b.setSelected(!b.isSelected()); fireEditingStopped(); } } }); CheckBoxEditorRenderer cer = new CheckBoxEditorRenderer(); TableColumn c = table.getColumnModel().getColumn(1); c.setCellRenderer(cer); c.setCellEditor(cer); c.setPreferredWidth(180); #spandel #spanend JPanel p = new JPanel(new BorderLayout()); p.add(new JScrollPane(table)); 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 EnumSetTest().makeUI()); f.setSize(320,200); f.setLocationRelativeTo(null); f.setVisible(true); } #spandel } #spanend #spandel class CheckBoxPanel extends JPanel { #spanend public final JCheckBox[] buttons; public CheckBoxPanel(String[] t) { super(); setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); buttons = new JCheckBox[t.length]; for (int i=0; i<buttons.length; i++) { add(buttons[i] = new JCheckBox(t[i])); }); } InputMap im = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_R, 0), title[0]); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), title[1]); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, 0), title[2]); } #spandel } #spanend #spandel enum User { OTHER, GROUP, OWNER; } #spanend #spandel class CheckBoxEditorRenderer extends AbstractCellEditor #spanend implements TableCellRenderer, TableCellEditor { protected final String[] title = {"owner", "group", "other"}; protected final CheckBoxPanel editor = new CheckBoxPanel(title); protected final CheckBoxPanel renderer = new CheckBoxPanel(title); protected void updateButtons(CheckBoxPanel p, Object v) { @SuppressWarnings("unchecked") EnumSet<User> f = (v==null)? EnumSet.noneOf(User.class) :(EnumSet<User>)v; p.buttons[0].setSelected(f.contains(User.OWNER)); p.buttons[1].setSelected(f.contains(User.GROUP)); p.buttons[2].setSelected(f.contains(User.OTHER)); } @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) { updateButtons(renderer, value); return renderer; } #spanadd #spanend @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { updateButtons(editor, value); return editor; Object value, boolean isSelected, int row, int column) { updateButtons(value); return this; } #spanadd #spanend @Override public Object getCellEditorValue() { EnumSet<User> f = EnumSet.noneOf(User.class); if (editor.buttons[0].isSelected()) f.add(User.OWNER); if (editor.buttons[1].isSelected()) f.add(User.GROUP); if (editor.buttons[2].isSelected()) f.add(User.OTHER); return f; int i = 0; if (buttons[0].isSelected()) i |= 1 << 2; if (buttons[1].isSelected()) i |= 1 << 1; if (buttons[2].isSelected()) i |= 1 << 0; return i; } #spandel } #spanend #spanadd #spanend // Copied from AbstractCellEditor protected EventListenerList listenerList = new EventListenerList(); transient protected ChangeEvent changeEvent = null; // ...
解説
-
JTable
のセル内に3
つのJCheckBox
を配置したJPanel
を作成- この
JPanel
をCellRenderer
用とCellEditor
用として別々に使用
- この
-
JCheckBox
をマウスでクリックすると直下にあるJCheckBox
の選択状態のみ更新 - 編集中にカラムヘッダの移動やリサイズ(
JFrame
などのリサイズに連動)などが発生してもチェックした内容がリセットされないようにCellEditor
のチェックボックスがクリックされたらfireEditingStopped()
メソッドを呼び出して編集を終了し更新を確定する