JTree:为各个组设置自定义打开/关闭图标

  1. 我知道如何在JTree中设置自定义叶子图标
  2. 我知道如何为所有组节点设置自定义关闭/打开图标

但我不能根据组节点名称设置自定义打开/关闭图标,例如节点可以称为电子邮件(因此有一个包络图标很好)或者一组可能被称为任务等等。

我试图通过重写类DefaultTreeCellRenderergetTreeCellRendererComponent方法来做到这一点

但是更改当前nodeicon只会影响下一个节点!

如何为各个组设置自定义打开/关闭图标?

请看一下我的代码:

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节点的closedopen图标:

iamge

 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方法,并根据该值更改这些方法的返回值。 我个人不会因为它改变了渲染器的记录行为而勇敢