Swing/CheckBoxNodeEditor のバックアップ(No.25)
- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- 現在との差分 - Visual を表示
- ソース を表示
- Swing/CheckBoxNodeEditor へ行く。
- 1 (2012-02-06 (月) 14:38:59)
- 2 (2012-02-07 (火) 13:58:43)
- 3 (2012-03-23 (金) 17:43:32)
- 4 (2012-05-10 (木) 10:52:04)
- 5 (2012-05-11 (金) 16:50:47)
- 6 (2012-12-13 (木) 15:41:34)
- 7 (2013-08-17 (土) 15:37:51)
- 8 (2014-02-18 (火) 15:23:02)
- 9 (2014-03-04 (火) 02:49:03)
- 10 (2014-03-04 (火) 11:06:52)
- 11 (2014-07-04 (金) 15:12:37)
- 12 (2014-08-15 (金) 19:46:41)
- 13 (2014-09-17 (水) 13:10:51)
- 14 (2014-10-22 (水) 00:52:41)
- 15 (2014-11-26 (水) 02:34:41)
- 16 (2015-02-06 (金) 11:59:40)
- 17 (2015-04-02 (木) 15:09:47)
- 18 (2017-02-22 (水) 13:58:44)
- 19 (2017-11-02 (木) 15:34:40)
- 20 (2017-12-28 (木) 22:28:33)
- 21 (2018-02-24 (土) 19:51:30)
- 22 (2019-05-22 (水) 19:35:38)
- 23 (2019-12-18 (水) 19:52:49)
- 24 (2021-06-19 (土) 17:20:17)
- 25 (2022-08-20 (土) 22:15:25)
- category: swing
folder: CheckBoxNodeEditor
title: JTreeのすべてのノードにJCheckBoxを追加する
tags: [JTree, JCheckBox, TreeCellRenderer, TreeCellEditor, TreeModelListener, Icon]
author: aterai
pubdate: 2012-02-06T14:38:59+09:00
description: JTreeのすべてのノードに編集可能なJCheckBoxを追加します。
image:
hreflang:
href: https://java-swing-tips.blogspot.com/2012/02/jcheckbox-node-jtree.html lang: en
概要
JTree
のすべてのノードに編集可能なJCheckBox
を追加します。
Screenshot
Advertisement
サンプルコード
class CheckBoxNodeEditor extends TriStateCheckBox implements TreeCellEditor {
private DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
private final JPanel panel = new JPanel(new BorderLayout());
private String str = null;
public CheckBoxNodeEditor() {
super();
this.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
// System.out.println("actionPerformed: stopCellEditing");
stopCellEditing();
}
});
panel.setFocusable(false);
panel.setRequestFocusEnabled(false);
panel.setOpaque(false);
panel.add(this, BorderLayout.WEST);
this.setOpaque(false);
}
@Override public Component getTreeCellEditorComponent(
JTree tree, Object value, boolean isSelected,
boolean expanded, boolean leaf, int row) {
JLabel l = (JLabel) renderer.getTreeCellRendererComponent(
tree, value, true, expanded, leaf, row, true);
l.setFont(tree.getFont());
if (value instanceof DefaultMutableTreeNode) {
this.setEnabled(tree.isEnabled());
this.setFont(tree.getFont());
Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
if (userObject instanceof CheckBoxNode) {
CheckBoxNode node = (CheckBoxNode) userObject;
if (node.status == Status.INDETERMINATE) {
setIcon(new IndeterminateIcon());
} else {
setIcon(null);
}
l.setText(node.label);
setSelected(node.status == Status.SELECTED);
str = node.label;
}
// panel.add(this, BorderLayout.WEST);
panel.add(l);
return panel;
}
return l;
}
@Override public Object getCellEditorValue() {
return new CheckBoxNode(str, isSelected() ? Status.SELECTED : Status.DESELECTED);
}
@Override public boolean isCellEditable(EventObject e) {
if (e instanceof MouseEvent && e.getSource() instanceof JTree) {
MouseEvent me = (MouseEvent) e;
JTree tree = (JTree) e.getSource();
TreePath path = tree.getPathForLocation(me.getX(), me.getY());
Rectangle r = tree.getPathBounds(path);
if (r == null) {
return false;
}
Dimension d = getPreferredSize();
r.setSize(new Dimension(d.width, r.height));
if (r.contains(me.getPoint())) {
return true;
}
}
return false;
}
@Override public void updateUI() {
super.updateUI();
setName("Tree.cellEditor");
if (panel != null) {
//panel.removeAll(); // ??? Change to Nimbus LnF, JDK 1.6.0
panel.updateUI();
//panel.add(this, BorderLayout.WEST);
}
// ???#1: JDK 1.6.0 bug??? @see 1.7.0 DefaultTreeCellRenderer#updateUI()
// if (System.getProperty("java.version").startsWith("1.6.0")) {
// renderer = new DefaultTreeCellRenderer();
// }
}
// ...
View in GitHub: Java, Kotlin解説
JCheckBox
を継承するTreeCellEditor
、TreeCellRenderer
を作成TreeCellEditor#getTreeCellEditorComponent(...)
などはこのJCheckBox
、JLabel
(文字列、アイコン)などを含むJPanel
を生成して返す
- マウスクリックなどでノードのチェック状態が変更されたら子ノードと親ノードの選択状態も更新する必要があるので、
TreeModelListener
をモデルに設定して監視 JPanel
を継承するTreeCellEditor
とTreeCellRenderer
でも、JDK 1.7.0
、JDK 1.6.0_30
などでは問題なく動作可能
class CheckBoxNodeRenderer extends JPanel implements TreeCellRenderer {
private DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
private final TriStateCheckBox check = new TriStateCheckBox();
public CheckBoxNodeRenderer() {
super(new BorderLayout());
String uiName = getUI().getClass().getName();
if (uiName.contains("Synth") && System.getProperty("java.version").startsWith("1.7.0")) {
System.out.println("XXX: FocusBorder bug?, JDK 1.7.0, Nimbus start LnF");
renderer.setBackgroundSelectionColor(new Color(0x0, true));
}
setFocusable(false);
setRequestFocusEnabled(false);
setOpaque(false);
add(check, BorderLayout.WEST);
check.setOpaque(false);
}
@Override public Component getTreeCellRendererComponent(
JTree tree, Object value, boolean selected,
boolean expanded, boolean leaf, int row, boolean hasFocus) {
JLabel l = (JLabel) renderer.getTreeCellRendererComponent(
tree, value, selected, expanded, leaf, row, hasFocus);
l.setFont(tree.getFont());
if (value instanceof DefaultMutableTreeNode) {
check.setEnabled(tree.isEnabled());
check.setFont(tree.getFont());
Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
if (userObject instanceof CheckBoxNode) {
CheckBoxNode node = (CheckBoxNode) userObject;
if (node.status == Status.INDETERMINATE) {
check.setIcon(new IndeterminateIcon());
} else {
check.setIcon(null);
}
l.setText(node.label);
check.setSelected(node.status == Status.SELECTED);
}
add(l);
return this;
}
return l;
}
@Override public void updateUI() {
super.updateUI();
if (check != null) {
// removeAll(); // ??? Change to Nimbus LnF, JDK 1.6.0
check.updateUI();
// add(check, BorderLayout.WEST);
}
setName("Tree.cellRenderer");
// ???#1: JDK 1.6.0 bug??? @see 1.7.0 DefaultTreeCellRenderer#updateUI()
// if (System.getProperty("java.version").startsWith("1.6.0")) {
// renderer = new DefaultTreeCellRenderer();
// }
}
}
JDK 1.6.0
でLookAndFeel
をNimbus
などに変更すると、セルエディタなどが更新されず、表示が不正になる場合があるので、JTree#updateUI()
を以下のようにオーバーライドして回避
JTree tree = new JTree() {
@Override public void updateUI() {
setCellRenderer(null);
setCellEditor(null);
super.updateUI();
//???#1: JDK 1.6.0 bug??? Nimbus LnF
setCellRenderer(new CheckBoxNodeRenderer());
setCellEditor(new CheckBoxNodeEditor());
}
};
public CheckBoxNodeRenderer() {
super();
String uiName = getUI().getClass().getName();
if (uiName.contains("Synth") && System.getProperty("java.version").startsWith("1.7.0")) {
System.out.println("XXX: FocusBorder bug?, JDK 1.7.0, Nimbus start LnF");
renderer.setBackgroundSelectionColor(new Color(0x0, true));
}
// ...
JDK 1.7.0
で、ノードのチェックボックスをクリックしても、初回だけ反応しない1.7.0_60
で修正されているJDK 1.6.0_30
などは問題なしTreeCellEditor#isCellEditable()
をオーバーライドして、初回のみセルエディタのサイズを以下のように設定JDK 1.8.0
では、修正されている- Bug ID: JDK-8023474 First mousepress doesn't start editing in JTree
if (isFirstTime && System.getProperty("java.version").startsWith("1.7.0")) {
System.out.println("XXX: Java 7, only on first run\n" + getBounds());
setBounds(new Rectangle(0, 0, d.width, r.height));
}