【问题标题】:How to set Jtree node icon dynamically如何动态设置Jtree节点图标
【发布时间】:2015-07-23 09:16:36
【问题描述】:

我想为分组和未分组的节点显示单独的图标。我创建了一个 customTreeCellRender。下面给出了我的示例代码。在 for 循环中,奇数的一个节点有一个图标,偶数有另一个。但不要更改节点的图标。在我的应用程序,从 db 填充树节点并根据某些条件进行分组。这是一个示例可运行代码。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.net.MalformedURLException;
import java.net.URL;

import javax.swing.ImageIcon;
import javax.swing.JDialog;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;

public class TestTree extends JDialog {

    JTree tree;

    DefaultTreeModel treeModel;

    public TestTree() {
        setSize(300, 800);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        System.out.println(getContentPane().getBackground());
    }

    protected static ImageIcon createImageIcon(String path) throws MalformedURLException {
        java.net.URL imgURL = new URL(path);
        if (imgURL != null) {
            return new ImageIcon(imgURL);
        } else {
            System.err.println("Couldn't find file: " + path);
            return null;
        }
    }

    public void init() throws MalformedURLException {
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Numbers");
        treeModel = new DefaultTreeModel(root);
        tree = new JTree(treeModel);
        tree.setBackground(new Color(238, 238, 244));
        tree.setOpaque(true);

        CustomIconRenderer customIconRenderer = new CustomIconRenderer(true);
        customIconRenderer.setTextSelectionColor(Color.white);
        customIconRenderer.setBackgroundSelectionColor(Color.blue);
        customIconRenderer.setBorderSelectionColor(Color.black);
        customIconRenderer.setBackgroundNonSelectionColor(new Color(238, 238,
                244));
        ImageIcon icon = createImageIcon("http://i.stack.imgur.com/wCF8S.png");
        customIconRenderer.setLeafIcon(icon);


        for (int i = 0; i < 10; i++) {
            if (i % 2 == 0) {
                DefaultMutableTreeNode subroot = new DefaultMutableTreeNode(
                        "node_" + i);
                root.add(subroot);

                    tree.setCellRenderer(new CustomIconRenderer(false));

                if (i % 3 == 0) {
                    for (int j = 10; j < 15; j++) {
                        DefaultMutableTreeNode leaf = new DefaultMutableTreeNode(
                                "node_" + j);
                        subroot.add(leaf);
                    }
                }

            } else {
                DefaultMutableTreeNode subroot = new DefaultMutableTreeNode(
                        "node_" + i);
                root.add(subroot);
                tree.setCellRenderer(new CustomIconRenderer(true));
                if (i % 4 == 0) {
                    for (int j = 15; j < 20; j++) {
                        DefaultMutableTreeNode leaf = new DefaultMutableTreeNode(
                                "node_" + j);
                        subroot.add(leaf);
                    }

                }

            }
        }

        for (int i = 0; i < tree.getRowCount(); i++) {
            tree.expandRow(i);
        }

        tree.setCellRenderer(customIconRenderer);

        getContentPane().add(tree, BorderLayout.CENTER);
    }

    public static void main(String args[]) throws MalformedURLException {
        TestTree tt = new TestTree();
        tt.init();
        tt.setVisible(true);
    }
}
class CustomIconRenderer extends DefaultTreeCellRenderer {
    /**
     * 
     */
    private static final long serialVersionUID = 967937360839244309L;
    ImageIcon groupedIcon;
    ImageIcon unGroupedIcon;
    boolean grouped;

    public CustomIconRenderer() {

    }

    public CustomIconRenderer(boolean grouped) throws MalformedURLException {
        this.grouped = grouped;
        URL url=new URL("http://i.stack.imgur.com/wCF8S.png");
        URL url1=new URL("http://i.stack.imgur.com/T5uTa.png");
        groupedIcon = new ImageIcon(url1
                );
        unGroupedIcon = new ImageIcon(url
                );
    }
@Override
    public Component getTreeCellRendererComponent(JTree tree, Object value,
            boolean sel, boolean expanded, boolean leaf, int row,
            boolean hasFocus) {

        super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf,
                row, hasFocus);

        Object nodeObj = ((DefaultMutableTreeNode) value).getUserObject();
        // check whatever you need to on the node user object
        if (grouped) {
            setIcon(unGroupedIcon);
        } else {
            System.out.println("reached");
            setIcon(groupedIcon);
        }
        return this;
    }
}

【问题讨论】:

  • 添加了可运行的正确示例
  • 1) MCVE 需要是一个源文件(可以包含多个非公共类)并包含导入。 2) 如果没有您 PC 上的图像文件,我们将无法运行它并查看问题!例如,获取图像的一种方法是热链接到在this Q&A 中看到的图像。
  • 加一个用于添加 MCVE。我正在尝试重新开放,但仍需要另外两张公开投票。同时,将public Component getTreeCellRendererComponent(.. 更改为@Override public Component getTreeCellRendererComponent(.. 以显示编译器消息。
  • “在 for 循环中,奇数一个节点有一个图标,偶数有另一个。” 好的。你所说的“奇怪”到底是什么意思?他们是那些文本以奇数结尾的吗?添加节点时,奇数是“每隔一个”吗?还有什么..?
  • 奇数文本以奇数结尾的文本

标签: java swing jtree treecellrenderer


【解决方案1】:

原始代码中有几个错误,最明显的是:

  • 每次添加节点时设置一个单元格渲染器(一棵树只能有一个单元格渲染器,因此“最后一个添加”获胜)。
  • 期望您为获取树单元格渲染器而编写的稍作改动的方法会被调用。 (你做了我在评论中提出的那个实验,对吧?)

我认为这更符合要求。请注意,我试图尽可能接近原始代码。我会以不同的方式处理它。

  • 此示例: 检查传递给方法的valueString 值,以获取单元格渲染器以查看它是否包含_ 字符,然后拆分字符串并解析最后一部分返回一个整数值。
  • 应该怎么做:传递Integer 对象作为树叶。在单元格渲染器中检查值是 Integer 的一个实例,如果是,则在数字前加上 node_ ..

import java.awt.*;
import java.net.*;
import javax.swing.*;
import javax.swing.tree.*;

public class TestTree extends JDialog {

    JTree tree;

    DefaultTreeModel treeModel;

    public TestTree() {
        setSize(300, 800);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        System.out.println(getContentPane().getBackground());
    }

    protected static ImageIcon createImageIcon(String path) throws MalformedURLException {
        java.net.URL imgURL = new URL(path);
        if (imgURL != null) {
            return new ImageIcon(imgURL);
        } else {
            System.err.println("Couldn't find file: " + path);
            return null;
        }
    }

    public void init() throws MalformedURLException {
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Numbers");
        treeModel = new DefaultTreeModel(root);
        tree = new JTree(treeModel);
        tree.setBackground(new Color(238, 238, 244));
        tree.setOpaque(true);

        CustomIconRenderer customIconRenderer = new CustomIconRenderer();
        customIconRenderer.setTextSelectionColor(Color.white);
        customIconRenderer.setBackgroundSelectionColor(Color.blue);
        customIconRenderer.setBorderSelectionColor(Color.black);
        customIconRenderer.setBackgroundNonSelectionColor(new Color(238, 238,
                244));
        ImageIcon icon = createImageIcon("http://i.stack.imgur.com/wCF8S.png");
        customIconRenderer.setLeafIcon(icon);
        tree.setCellRenderer(new CustomIconRenderer());

        for (int i = 0; i < 10; i++) {
            if (i % 2 == 0) {
                DefaultMutableTreeNode subroot = new DefaultMutableTreeNode(
                        "node_" + i);
                root.add(subroot);

                if (i % 3 == 0) {
                    for (int j = 10; j < 15; j++) {
                        DefaultMutableTreeNode leaf = new DefaultMutableTreeNode(
                                "node_" + j);
                        subroot.add(leaf);
                    }
                }
            } else {
                DefaultMutableTreeNode subroot = new DefaultMutableTreeNode(
                        "node_" + i);
                root.add(subroot);
                if (i % 4 == 0) {
                    for (int j = 15; j < 20; j++) {
                        DefaultMutableTreeNode leaf = new DefaultMutableTreeNode(
                                "node_" + j);
                        subroot.add(leaf);
                    }
                }
            }
        }

        for (int i = 0; i < tree.getRowCount(); i++) {
            tree.expandRow(i);
        }

        tree.setCellRenderer(customIconRenderer);

        getContentPane().add(tree, BorderLayout.CENTER);
    }

    public static void main(String args[]) throws MalformedURLException {
        TestTree tt = new TestTree();
        tt.init();
        tt.setVisible(true);
    }
}

class CustomIconRenderer extends DefaultTreeCellRenderer {

    /**
     *
     */
    private static final long serialVersionUID = 967937360839244309L;
    ImageIcon groupedIcon;
    ImageIcon unGroupedIcon;

    public CustomIconRenderer() throws MalformedURLException {
        URL url = new URL("http://i.stack.imgur.com/wCF8S.png");
        URL url1 = new URL("http://i.stack.imgur.com/T5uTa.png");
        groupedIcon = new ImageIcon(url1);
        unGroupedIcon = new ImageIcon(url);
    }

    @Override
    public Component getTreeCellRendererComponent(JTree tree, Object value,
            boolean sel, boolean expanded, boolean leaf, int row,
            boolean hasFocus) {

        super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf,
                row, hasFocus);

        Object nodeObj = ((DefaultMutableTreeNode) value).getUserObject();
        String s = nodeObj.toString();
        System.out.println("s: " + s);
        boolean includesUnderscore = s.indexOf("_") > 0;
        if (includesUnderscore) {
            String lastPart = s.split("_")[1];
            int num = Integer.parseInt(lastPart);
            // check whatever you need to on the node user object
            if (num % 2 == 0) {
                setIcon(unGroupedIcon);
            } else {
                System.out.println("reached");
                setIcon(groupedIcon);
            }
        }
        return this;
    }
}

【讨论】:

  • 在我的应用程序中,从 db 填充树节点并根据不同条件设置图标对应于每个级别的节点。在这种情况下,我想将一个标志传递给 CustomRenderer 类。我可以在渲染类中定义另一个函数并设置全局变量值吗?
  • "我可以在渲染类中定义另一个函数并设置全局变量值吗。" 我真的不认为你明白只有 ever 单个单元格渲染器,无论存在多少树节点。你明白吗?顺便说一句 - 对我来说,“全局”意味着所有单元格渲染器的值相同(无论有多少),因此尝试使用全局变量以不同方式渲染不同的叶子并没有真正意义。我们中的一个很困惑,我希望我知道是哪一个!
  • 感谢 Andrew .applied 我的应用程序并得到它。
  • 很高兴你把它整理好了。 :)
【解决方案2】:

我创建了一个 customTreeCellRender。但没有更改图标

您不需要直接调用getTreeCellRendererComponent,而是让JTree 通过显式设置TreeCellRendererJTree 来处理它,如Oracle tutorial 中所述

tree.setCellRenderer(customIconRenderer);

【讨论】:

  • 上述教程为所有节点设置相同的图标。但我想为每个节点设置不同的图标。我不是直接调用 getTreeCellRendererComponent ,它是 CustomRender 类中的方法之一。而不是调用构造函数 I使用了这个方法,请注意方法调用过程中传递的参数个数。
猜你喜欢
  • 2014-01-08
  • 2013-02-04
  • 1970-01-01
  • 2011-01-13
  • 2021-07-14
  • 2012-11-27
  • 2012-02-22
  • 2017-05-05
相关资源
最近更新 更多