JTree:为各个组设置自定义打开/关闭图标
- 我知道如何在JTree中设置自定义叶子图标
- 我知道如何为所有组节点设置自定义关闭/打开图标
但我不能根据组节点名称设置自定义打开/关闭图标,例如节点可以称为电子邮件(因此有一个包络图标很好)或者一组可能被称为任务等等。
我试图通过重写类DefaultTreeCellRenderer
的getTreeCellRendererComponent
方法来做到这一点
但是更改当前node
的icon
只会影响下一个节点!
如何为各个组设置自定义打开/关闭图标?
请看一下我的代码:
Employee.java
package com.ehsunbehravesh.swing; import java.util.Random; public class Employee { public String name; public int id; public boolean isBoss; public Employee[] employees; public Employee(String name, boolean isBoss) { this.name = name; this.isBoss = isBoss; this.id = new Random(System.currentTimeMillis()).nextInt(Integer.MAX_VALUE); } @Override public String toString() { return this.name; } static String randomName() { String chars = "abcdefghijklmnopqrstuvwxyz"; StringBuilder builder = new StringBuilder(); Random r = new Random(System.currentTimeMillis()); int length = r.nextInt(10) + 1; for (int i = 0; i < length; i++) { builder.append(chars.charAt(r.nextInt(chars.length()))); } return builder.toString(); } }
CustomTreeNode.java
package com.ehsunbehravesh.swing; import javax.swing.ImageIcon; import javax.swing.tree.DefaultMutableTreeNode; public class CustomTreeNode extends DefaultMutableTreeNode { /** * The icon which is displayed on the JTree object. open, close, leaf icon. */ private ImageIcon icon; public CustomTreeNode(ImageIcon icon) { this.icon = icon; } public CustomTreeNode(ImageIcon icon, Object userObject) { super(userObject); this.icon = icon; } public CustomTreeNode(ImageIcon icon, Object userObject, boolean allowsChildren) { super(userObject, allowsChildren); this.icon = icon; } public ImageIcon getIcon() { return icon; } public void setIcon(ImageIcon icon) { this.icon = icon; } }
CustomeTreeCellRenderer.java
package com.ehsunbehravesh.swing; import java.awt.Component; import javax.swing.JTree; import javax.swing.tree.DefaultTreeCellRenderer; class CustomeTreeCellRenderer extends DefaultTreeCellRenderer { public CustomeTreeCellRenderer() { } @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { super.getTreeCellRendererComponent(tree, value, leaf, expanded, leaf, row, hasFocus); if (!leaf) { CustomTreeNode node = (CustomTreeNode) value; System.out.println(((Employee) node.getUserObject()).name); if (node.getIcon() != null) { System.out.println(node.getIcon().toString()); setClosedIcon(node.getIcon()); setOpenIcon(node.getIcon()); } else { setClosedIcon(getDefaultClosedIcon()); setClosedIcon(getDefaultOpenIcon()); setOpenIcon(getDefaultOpenIcon()); } } return this; } }
Test1.java
package com.ehsunbehravesh.swing; import java.awt.BorderLayout; import java.awt.Color; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JTree; import javax.swing.tree.DefaultTreeModel; class TreeSample { public static void main(String args[]) { JFrame f = new JFrame("JTree Sample"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel pnlMain = new JPanel(new BorderLayout()); pnlMain.setBackground(Color.white); createTree(pnlMain); f.setContentPane(pnlMain); f.setSize(300, 200); f.setVisible(true); } private static void createTree(JPanel pnlMain) { Employee bigBoss = new Employee(Employee.randomName(), true); Employee[] level1 = new Employee[5]; bigBoss.employees = level1; for (int i = 0; i < level1.length; i++) { level1[i] = new Employee(Employee.randomName(), true); } for (int i = 0; i < level1.length; i++) { Employee employee = level1[i]; if (employee.isBoss) { int count = 5; employee.employees = new Employee[count]; for (int j = 0; j < employee.employees.length; j++) { employee.employees[j] = new Employee(Employee.randomName(), false); } } } CustomTreeNode root = new CustomTreeNode(new ImageIcon("images/Circle_3.gif"), bigBoss); DefaultTreeModel model = new DefaultTreeModel(root); for (Employee employee : bigBoss.employees) { CustomTreeNode boss = new CustomTreeNode(new ImageIcon("images/Circle_2.gif"), employee); root.add(boss); if (employee.isBoss) { for (Employee employee1 : employee.employees) { CustomTreeNode emp = new CustomTreeNode(new ImageIcon("images/Circle_1.gif"), employee1); boss.add(emp); } } } JTree tree = new JTree(model); tree.setCellRenderer(new CustomeTreeCellRenderer()); pnlMain.add(tree, BorderLayout.CENTER); } }
在TreeCellRenderer
,您可以根据需要使用setOpenIcon()
和setClosedIcon()
以及与模型相关的已定义参数和谓词。 给定一个具有默认JTree
模型的树,下面的TreeRenderer
将使用sports
节点的closed
和open
图标:
private static class TreeRenderer extends DefaultTreeCellRenderer { private static final Icon closed = (Icon) UIManager.get("InternalFrame.maximizeIcon"); private static final Icon open = (Icon) UIManager.get("InternalFrame.minimizeIcon"); @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean exp, boolean leaf, int row, boolean hasFocus) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; String s = node.getUserObject().toString(); if ("sports".equals(s)) { setOpenIcon(open); setClosedIcon(closed); } else { setOpenIcon(getDefaultOpenIcon()); setClosedIcon(getDefaultClosedIcon()); } super.getTreeCellRendererComponent( tree, value, sel, exp, leaf, row, hasFocus); return this; } }
另请参见此相关示例 。
运行代码之后,您尝试加载的图像似乎“意味着”嵌入到您的应用程序中(也就是说,它们不会驻留在应用程序上下文的磁盘外的某些位置)。
所以不要这样做……
CustomTreeNode root = new CustomTreeNode(new ImageIcon("images/Circle_3.gif"), bigBoss);
尝试做这样的事……
CustomTreeNode root = new CustomTreeNode(new ImageIcon(ImageIO.read(getClass().getResource("/images/Circle_3.gif"))), bigBoss);
代替。 这将使Java在其类路径(包括任何JAR资源)中查找以查找图像。
当我运行没有此修复程序的代码时,没有任何工作,当我更新它以使用此function时,它工作正常。
注意: ImageIO#read
抛出IOException
所以请注意它
更新
经过多次刮擦……我改变了细胞渲染器,看起来像这样……
class CustomeTreeCellRenderer extends DefaultTreeCellRenderer { public CustomeTreeCellRenderer() { } @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { // if (!leaf) { CustomTreeNode node = (CustomTreeNode) value; if (node.getIcon() != null) { System.out.println(node + " - " + node.getIcon()); setClosedIcon(node.getIcon()); setOpenIcon(node.getIcon()); setLeafIcon(node.getIcon()); } else { System.out.println(node + " - default"); setClosedIcon(getDefaultClosedIcon()); setLeafIcon(getDefaultLeafIcon()); setOpenIcon(getDefaultOpenIcon()); } // } super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); return this; } }
它清除了一切……
调用setXxxIcon
不会影响当前渲染器,但会影响将来的渲染器。 那是。 如果在调用setOpenIcon
之后调用super.getTreeCellRendererComponent
,它将不会影响当前渲染器,但它将影响对super.getTreeCellRendererComponent
的下一次调用,因为set方法只是设置类变量的值。
额外
Trashgod对依赖于实施及其现在的运作方式做出了有价值的评论。
您应该使用基于传递给它的参数所需的图标,而不是在getTreeCellRendererComponent
方法中调用DefaultTreeCellRenderer#setXxxIcon
,而应该调用DefaultTreeCellRenderer#setIcon
。
这意味着您可以先调用super.getTreeCellRendererComponent
,然后覆盖其后的图标行为。
您还可以获取对Object
值的引用并覆盖DefaultTreeCellRenderer#getXxxIcon
方法,并根据该值更改这些方法的返回值。 我个人不会因为它改变了渲染器的记录行为而勇敢