Swing/TreeComboBox のバックアップ(No.12)
- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- 現在との差分 - Visual を表示
- ソース を表示
- Swing/TreeComboBox へ行く。
- 1 (2011-07-12 (火) 19:35:10)
- 2 (2011-07-13 (水) 19:02:23)
- 3 (2012-12-19 (水) 22:13:50)
- 4 (2013-08-17 (土) 00:55:42)
- 5 (2015-01-09 (金) 14:16:08)
- 6 (2015-03-19 (木) 16:33:15)
- 7 (2016-05-27 (金) 15:32:36)
- 8 (2017-08-29 (火) 16:10:07)
- 9 (2018-02-22 (木) 19:13:58)
- 10 (2020-02-13 (木) 15:13:08)
- 11 (2021-07-30 (金) 04:22:23)
- 12 (2024-02-10 (土) 17:44:41)
- category: swing folder: TreeComboBox title: JComboBoxのItemをTree状に表示する tags: [JComboBox, TreeModel] author: aterai pubdate: 2011-07-11T15:16:42+09:00 description: JComboBoxのドロップダウンリストに表示するItemをTree状に配置します。 image:
概要
JComboBox
のドロップダウンリストに表示するItem
をTree
状に配置します。
Screenshot
Advertisement
サンプルコード
class TreeComboBox<E extends TreeNode> extends JComboBox<E> {
private boolean isNotSelectableIndex;
private final Action up = new AbstractAction() {
@Override public void actionPerformed(ActionEvent e) {
int si = getSelectedIndex();
for (int i = si - 1; i >= 0; i--) {
if (getItemAt(i).isLeaf()) {
setSelectedIndex(i);
break;
}
}
}
};
private final Action down = new AbstractAction() {
@Override public void actionPerformed(ActionEvent e) {
int si = getSelectedIndex();
for (int i = si + 1; i < getModel().getSize(); i++) {
if (getItemAt(i).isLeaf()) {
setSelectedIndex(i);
break;
}
}
}
};
@Override public void updateUI() {
super.updateUI();
ListCellRenderer<? super E> renderer = getRenderer();
setRenderer(new ListCellRenderer<E>() {
@Override public Component getListCellRendererComponent(
JList<? extends E> list, E value, int index,
boolean isSelected, boolean cellHasFocus) {
JLabel l = (JLabel) renderer.getListCellRendererComponent(
list, value, index, isSelected, cellHasFocus);
l.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
if (index >= 0 && value instanceof DefaultMutableTreeNode) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
int indent = Math.max(0, node.getLevel() - 1) * 16;
l.setBorder(BorderFactory.createEmptyBorder(1, indent + 1, 1, 1));
if (!value.isLeaf()) {
l.setForeground(Color.WHITE);
l.setBackground(Color.GRAY.darker());
}
}
return l;
}
});
EventQueue.invokeLater(() -> {
ActionMap am = getActionMap();
am.put("selectPrevious3", up);
am.put("selectNext3", down);
InputMap im = getInputMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "selectPrevious3");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_KP_UP, 0), "selectPrevious3");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "selectNext3");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_KP_DOWN, 0), "selectNext3");
});
}
@Override public void setPopupVisible(boolean v) {
if (!v && isNotSelectableIndex) {
isNotSelectableIndex = false;
} else {
super.setPopupVisible(v);
}
}
@Override public void setSelectedIndex(int index) {
TreeNode node = getItemAt(index);
if (Objects.nonNull(node) && node.isLeaf()) {
super.setSelectedIndex(index);
} else {
isNotSelectableIndex = true;
}
}
}
View in GitHub: Java, Kotlin解説
上記のサンプルでは、TreeModel
から取得したTreeNode
をJComboBox
のItem
として、ドロップダウンリストに表示しています。
TreeNode#isLeaf()
の場合のみ選択可能に設定- 第
0
レベルのルートノードは非表示で第1
レベルノードのインデントは0
に設定 - 第
2
レベル以降の子ノードのインデントはBorderFactory.createEmptyBorder(1, indent + 1, 1, 1)
で設定
TreeCellRenderer
を使用してノードアイコンなどを表示する場合のサンプル
import java.awt.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeCellRenderer;
public final class TreeComboBoxTest {
private Component makeUI() {
DefaultMutableTreeNode root = (DefaultMutableTreeNode) new JTree().getModel().getRoot();
JPanel p = new JPanel(new BorderLayout());
p.add(new TreeComboBox(root), BorderLayout.NORTH);
p.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch(Exception ex) {
throw new IllegalArgumentException(ex);
}
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new TreeComboBoxTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}
class TreeComboBox extends JComboBox<DefaultMutableTreeNode> {
public TreeComboBox(DefaultMutableTreeNode root) {
super();
DefaultComboBoxModel<DefaultMutableTreeNode> m = new DefaultComboBoxModel<>();
Collections.list((Enumeration<?>) root.preorderEnumeration()).stream()
.filter(DefaultMutableTreeNode.class::isInstance)
.map(DefaultMutableTreeNode.class::cast)
.filter(n -> !n.isRoot())
.forEach(m::addElement);
setModel(m);
}
@Override
public void updateUI() {
super.updateUI();
JTree dummyTree = new JTree();
TreeCellRenderer renderer = dummyTree.getCellRenderer();
ListCellRenderer<? super DefaultMutableTreeNode> r = getRenderer();
setRenderer((list, value, index, isSelected, cellHasFocus) -> {
Component c = r.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value == null) {
return c;
}
if (index < 0) {
String txt = Arrays.stream(value.getPath())
.filter(DefaultMutableTreeNode.class::isInstance)
.map(DefaultMutableTreeNode.class::cast)
.filter(n -> !n.isRoot())
.map(Objects::toString)
.collect(Collectors.joining(" / "));
((JLabel) c).setText(txt);
return c;
} else {
boolean leaf = value.isLeaf();
JLabel l = (JLabel) renderer.getTreeCellRendererComponent(
dummyTree, value, isSelected, true, leaf, index, false);
int childIndent = UIManager.getInt("Tree.leftChildIndent") +
UIManager.getInt("Tree.rightChildIndent");
int indent = Math.max(0, value.getLevel() - 1) * childIndent;
l.setBorder(BorderFactory.createEmptyBorder(1, indent + 1, 1, 1));
return l;
}
});
}
}
参考リンク
- Tree inside JComboBox - Santhosh Kumar's Weblog
TreeCellRenderer
を使用し、ノードアイコンなども含めてJTree
をドロップダウンリストに表示するサンプルがある
- JComboBoxのアイテムを選択不可にする