但我无法根据组节点名称设置自定义打开/关闭图标,例如,节点可以称为电子邮件(因此有信封图标很好),或者一个组可以称为任务等等。
我试图通过重写类DefaultTreeCellRenderer的getTreeCellRendererComponent方法来实现这一点
但是更改当前节点的图标只会影响下一个节点!
如何为单个组设置自定义打开/关闭图标?
请看看我的代码:
受雇者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);
}
}
如果我们需要组件(所以我们需要在第一步调用超级渲染器),设置所有树图标(打开、关闭、叶子)以使其正常工作是很重要的。
public java.awt.Component getTreeCellRendererComponent(javax.swing.JTree tree, Object value, boolean selected, boolean expanded, boolean isLeaf, int row, boolean focused) {
Component c = super.getTreeCellRendererComponent(tree, value, selected, expanded, isLeaf, row, focused);
DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
MyTreeNodeWrapper treeNodeWrapper = (MyTreeNodeWrapper) node.getUserObject();
Icon icon = treeNodeWrapper .getIcon();
setOpenIcon(icon);
setClosedIcon(icon);
setLeafIcon(icon);
if (!tree.isEnabled()) {
if (isLeaf) {
setDisabledIcon(getLeafIcon());
} else if (expanded) {
setDisabledIcon(getOpenIcon());
} else {
setDisabledIcon(getClosedIcon());
}
}
else {
if (isLeaf) {
setIcon(getLeafIcon());
} else if (expanded) {
setIcon(getOpenIcon());
} else {
setIcon(getClosedIcon());
}
}
return c;
}
如果没有,如上所述,我们只需要设置3种图标类型:
public java.awt.Component getTreeCellRendererComponent(javax.swing.JTree tree, Object value, boolean selected, boolean expanded, boolean isLeaf, int row, boolean focused) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
MyTreeNodeWrapper treeNodeWrapper = (MyTreeNodeWrapper ) node.getUserObject();
Icon icon = treeNodeWrapper .getIcon();
setOpenIcon(icon);
setClosedIcon(icon);
setLeafIcon(icon);
Component c = super.getTreeCellRendererComponent(tree, value, selected, expanded, isLeaf, row, focused);
return c;
}
运行代码后,您试图加载的图像似乎“意味着”嵌入到您的应用程序中(也就是说,它们并不位于应用程序上下文的磁盘外侧)。
所以与其这么做...
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资源)中查找图像。
当我在没有这个补丁的情况下运行代码时,一切都不起作用,当我更新它以使用这个特性时,它工作得很好。
注意: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不会影响当前渲染器,但会影响未来的渲染器。就是这样。如果您在调用super之后调用setOpenIcon。GetTreeCellRenderComponent,它不会影响当前渲染器,但会影响下一次调用super。getTreeCellRendererComponent,因为set方法只是设置类变量的值。
附加
垃圾神(Trashgod)对依赖实现及其现在的工作方式发表了宝贵的评论。
与在方法getTreeCellRendererComponent中调用DefaultTreeCellRenderer#setXxxIcon不同,您实际上只需根据传递给它的参数使用所需的图标调用DefaultTreeCellRenderer#setIcon。
这意味着您可以调用super。首先是GetTreeCellRenderComponent,然后覆盖其后面图标的行为。
您还可以获取对对象值的引用,覆盖DefaultTreeCellRenderer#getXxxIcon方法,并根据该值更改这些方法的返回值。就我个人而言,我不敢这么做,因为它改变了渲染器记录的行为
在TreeCellRenderer中,可以根据需要使用与模型相关的已定义参数和谓词。给定一棵树具有默认的JTree模型,下面的TreeRenderer将为体育节点使用关闭和打开图标:
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;
}
}
另请参见此相关示例。
我想为JTree中的每个节点设置一个不同的图标,实际上我是从数据库中加载每个节点,使用“while”,我将每个图标设置为根、叶或父。这样地: 我的所有声明都是全球性的: 这是我设置节点的代码: makeNode方法如下: 在用我的节点填充treemodel之后,我将模型设置为我的JTree: 但问题是。当我尝试设置图标时。我创建了一个名为myTreeRenler的子类,我使用它: 但它没有设置我想
问题内容: 我想为JTree中的每个节点设置一个不同的图标,实际上是从数据库中加载每个节点,并带有“ while”,我将每个图标设置为根,叶或父级。像这样: 我所有的声明都是全球性的: 这是我设置节点的代码: 方法makeNode是这样的: 在用节点填充treemodel之后,将模型设置为JTree: 但是问题是。当我尝试设置图标时。我创建一个名为myTreeRenderer的子类,并使用以下代码
问题内容: 我想将一列的Is Identity属性设置为off并在插入一个显式值后再次将其设置为on。我编写了以下查询: 尽管执行成功,但是表设计没有任何变化。请提出解决方案,这非常关键。 问题答案: 您提供的所有代码行都是禁用身份,以便您可以在身份列中插入特定的值- 通常,一次性完成此操作是必需的,例如,移动数据。标识仍然在列上,只是不起作用。从概念上讲,这类似于禁用和删除触发器之间的区别。
自定义开关控件(UISwitch)的外观。 [Code4App.com]
在ex-project中打开文件 在exvim中,你可以通过直接修改代码的形式自定义ex-project打开文件的行为. 主要通过编辑ex-project/autoload/exproject.vim, 找到exproject#confirm_select,添加你的代码. 在ctrlp中打开文件 ctrlp插件提供自定义的方式, 例子如下: let g:ctrlp_open_func = { 'f
我在嵌套的代码周围看到一些奇怪的行为 鉴于: 在Chrome中,这会导致 也就是说,它关闭开始标记并打开结束标记。我(当然)听说过“自动关闭标签”;我从没听说过“自动打开标签”。 IE11采用了一种不同的(可以说是更错误的)方式: 因此,它不会自动关闭打开的标记,但它会自动打开关闭的标记,从而导致不平衡的DOM树。 无论如何,我很好奇解决这个问题的正确途径是什么;我应该打开Chrome和IE错误跟