Swing/TreeComboBox の変更点
- 追加された行はこの色です。
- 削除された行はこの色です。
- Swing/TreeComboBox へ行く。
- Swing/TreeComboBox の差分を削除
--- 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: https://lh6.googleusercontent.com/-5GlQEjeLoH8/ThqUIL9b4UI/AAAAAAAAA_E/9h5dxYzSSm8/s800/TreeComboBox.png --- * 概要 [#summary] `JComboBox`のドロップダウンリストに表示する`Item`を`Tree`状に配置します。 #download(https://lh6.googleusercontent.com/-5GlQEjeLoH8/ThqUIL9b4UI/AAAAAAAAA_E/9h5dxYzSSm8/s800/TreeComboBox.png) * サンプルコード [#sourcecode] #code(link){{ 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; } } } }} * 解説 [#explanation] 上記のサンプルでは、`TreeModel`から取得した`TreeNode`を`JComboBox`の`Item`として、ドロップダウンリストに表示しています。 - `TreeNode#isLeaf()`の場合のみ選択可能に設定 -- [[JComboBoxのアイテムを選択不可にする>Swing/DisableItemComboBox]] - 第`0`レベルのルートノードは非表示で第`1`レベルノードのインデントは`0`に設定 - 第`2`レベル以降の子ノードのインデントは`BorderFactory.createEmptyBorder(1, indent + 1, 1, 1)`で設定 ---- - `TreeCellRenderer`を使用してノードアイコンなどを表示する場合のサンプル #code{{ 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.add(new TreeComboBox(makeRoot()), BorderLayout.NORTH); p.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); return p; } private static DefaultMutableTreeNode makeRoot() { return (DefaultMutableTreeNode) new JTree().getModel().getRoot(); } 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(); JTree sampleTree = new JTree(); TreeCellRenderer renderer = sampleTree.getCellRenderer(); ListCellRenderer<? super DefaultMutableTreeNode> r = getRenderer(); setRenderer((list, value, index, isSelected, cellHasFocus) -> { Component c = r.getListCellRendererComponent(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); sampleTree, 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; } }); } } }} * 参考リンク [#reference] - [http://www.jroller.com/santhosh/entry/tree_inside_jcombobox Tree inside JComboBox - Santhosh Kumar's Weblog] -- `TreeCellRenderer`を使用し、ノードアイコンなども含めて`JTree`をドロップダウンリストに表示するサンプルがある - [[JComboBoxのアイテムを選択不可にする>Swing/DisableItemComboBox]] * コメント [#comment] #comment - `src.zip`などが正しいディレクトリに配置されてなかったのを修正。 -- &user(aterai); &new{2011-07-13 (水) 19:02:23}; #comment