java JTree:为各个组设置自定义打开/关闭图标
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14096725/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JTree: Set custom open/closed icons for individual groups
提问by ehsun7b
- I know how to set custom leaf icons in JTree
- I know how to set custom closed/open icons for all group nodes
- 我知道如何在 JTree 中设置自定义叶子图标
- 我知道如何为所有组节点设置自定义关闭/打开图标
But I can not set custom open/closed icons based on the group node names, for example of node could be called Emails (so it is nice to have an envelop icon) or one group may be called tasks and so on.
但是我无法根据组节点名称设置自定义打开/关闭图标,例如节点可以称为电子邮件(所以有一个信封图标很好)或者一个组可以称为任务等等。
I tried to do this by overriding the getTreeCellRendererComponent
method of class DefaultTreeCellRenderer
我试图通过覆盖getTreeCellRendererComponent
类的方法来做到这一点DefaultTreeCellRenderer
But changing the icon
for the current node
will affect for the next node only!
但是更改icon
当前node
节点只会影响下一个节点!
How to set custom open/closed icons for individual groups?
如何为单个组设置自定义打开/关闭图标?
Please take a look at my code:
请看一下我的代码:
Employee.java
雇员.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
自定义树节点.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
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
测试1.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);
}
}
回答by trashgod
In your TreeCellRenderer
, you can use setOpenIcon()
and setClosedIcon()
as required in conjunction with the defined parameters and predicates related to your model. Given a tree having the default JTree
model, the TreeRenderer
below will use the closed
and open
icons for the sports
node:
在你的TreeCellRenderer
,你可以使用setOpenIcon()
,并setClosedIcon()
在与有关模型定义的参数和谓词结合必需的。给定具有默认JTree
模型的树,TreeRenderer
以下将使用节点的closed
和open
图标sports
:
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;
}
}
See also this related example.
另请参阅此相关示例。
回答by MadProgrammer
Having run you code, it would appear that the images you are trying to load are "meant" to be embedded within you application (that is, they don't reside some where on the disk out side of the application context).
运行您的代码后,您尝试加载的图像似乎“打算”嵌入到您的应用程序中(也就是说,它们并不驻留在应用程序上下文之外的磁盘上的某个位置)。
So instead of doing this...
所以,而不是这样做......
CustomTreeNode root = new CustomTreeNode(new ImageIcon("images/Circle_3.gif"), bigBoss);
Try doing something like this...
尝试做这样的事情......
CustomTreeNode root = new CustomTreeNode(new ImageIcon(ImageIO.read(getClass().getResource("/images/Circle_3.gif"))), bigBoss);
Instead. This will cause Java to look within it's class path (including any JAR resources) to find the images.
反而。这将导致 Java 在其类路径(包括任何 JAR 资源)中查找图像。
When I run you code without this fix, nothing worked, when I updated it to use this feature, it worked fine.
当我在没有此修复程序的情况下运行代码时,没有任何效果,当我更新它以使用此功能时,它运行良好。
NB: ImageIO#read
throws an IOException
so look out for it
注意:ImageIO#read
抛出一个IOException
所以要注意它
Updated
更新
After much head scratching...I changed the cell renderer to look like this...
经过多次挠头……我将单元渲染器更改为这样……
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;
}
}
It it cleared it all up...
它清除了一切......
Calling setXxxIcon
doesn't effect the current renderer, but the future renderer. That is. If you call setOpenIcon
AFTER you've already called super.getTreeCellRendererComponent
, it will not effect the current renderer, but it will effect the next call to super.getTreeCellRendererComponent
as the set method is simply setting the value of class variable.
调用setXxxIcon
不会影响当前的渲染器,但会影响未来的渲染器。那是。如果你在setOpenIcon
你已经调用之后调用super.getTreeCellRendererComponent
,它不会影响当前渲染器,但它会影响下一次调用,super.getTreeCellRendererComponent
因为 set 方法只是设置类变量的值。
Additional
额外的
Trashgod has made a valuable comment about relying on the implementation and the way it works now.
Trashgod 对依赖实现及其现在的工作方式提出了宝贵意见。
Instead of calling DefaultTreeCellRenderer#setXxxIcon
within the getTreeCellRendererComponent
method, you should actually simply call DefaultTreeCellRenderer#setIcon
, using the required icon based on the parameters passed to it.
而不是DefaultTreeCellRenderer#setXxxIcon
在getTreeCellRendererComponent
方法内调用,您实际上应该简单地调用DefaultTreeCellRenderer#setIcon
,使用基于传递给它的参数所需的图标。
This means you can call super.getTreeCellRendererComponent
first and then override the behavior of the icons after it.
这意味着您可以super.getTreeCellRendererComponent
先调用,然后在调用之后覆盖图标的行为。
You could also grab a reference to Object
value and override the DefaultTreeCellRenderer#getXxxIcon
methods and based on the value, change the return values of these methods. I personally, wouldn't courage this as it changes the documented behavior of the renderer
您还可以获取对Object
值的引用并覆盖DefaultTreeCellRenderer#getXxxIcon
方法,并根据值更改这些方法的返回值。我个人不会这样做,因为它改变了渲染器的记录行为