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

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

我试图通过覆盖getTreeCellRendererComponent类的方法来做到这一点DefaultTreeCellRenderer

但是改变icon当前node节点只会影响下一个节点!

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

请看一下我的代码:

雇员.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;
  }
}

测试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);
  }  
}
4

3 回答 3

10

在您的TreeCellRenderer中,您可以根据需要将setOpenIcon()setClosedIcon()与与您的模型相关的已定义参数和谓词一起使用。给定具有默认JTree模型的树,TreeRenderer下面将使用closedopen图标作为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;
    }
}

另请参阅此相关示例

于 2012-12-31T03:59:01.660 回答
5

运行代码后,您尝试加载的图像似乎“意味着”嵌入到您的应用程序中(也就是说,它们不驻留在应用程序上下文之外的磁盘上的某个位置)。

因此,与其这样做...

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不会影响当前的渲染器,但会影响未来的渲染器。那是。如果你在调用setOpenIcon之后调用super.getTreeCellRendererComponent,它不会影响当前的渲染器,但它会影响下一次调用,super.getTreeCellRendererComponent因为 set 方法只是设置类变量的值。

额外的

Trashgod 对依赖实施及其现在的工作方式发表了有价值的评论。

DefaultTreeCellRenderer#setXxxIcon而不是在方法中调用getTreeCellRendererComponent,您实际上应该简单地调用DefaultTreeCellRenderer#setIcon,使用基于传递给它的参数的所需图标。

这意味着您可以super.getTreeCellRendererComponent先调用,然后覆盖其后图标的行为。

您还可以获取对Objectvalue 的引用并覆盖DefaultTreeCellRenderer#getXxxIcon方法,并根据 value 更改这些方法的返回值。我个人不会鼓励这样做,因为它会改变渲染器的记录行为

于 2012-12-31T07:05:16.683 回答
0

如果我们需要组件(因此我们需要在第一步调用超级渲染器),设置所有树图标(打开、关闭、叶子)以使其正常工作很重要。

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;

        
}
于 2020-12-31T05:28:39.900 回答