【问题标题】:JTree node's changable tooltipJTree 节点可更改工具提示
【发布时间】:2012-06-20 09:04:37
【问题描述】:

我有一个填充了一些(自定义)节点的 JTree。我有一个类是 DefaultTreeCellRenderer 的子类,使用“MyTreeCellRenderer”我可以为树中的每个节点设置工具提示。它工作正常:填充了 JTree,设置了单元格渲染器,所有添加的节点都有工具提示。 问题是我不知道如何更改已填充树中某些节点的工具提示...怎么做?有没有办法为 JTree 中的一个节点“重新创建”单元格渲染器?

【问题讨论】:

  • 不知道您是如何构建 JToolTip 的,为了获得更好的帮助,请尽快发布 SSCCE

标签: java swing tooltip jtree renderer


【解决方案1】:

根据我对您问题的理解,您想触发树中特定节点的渲染。这应该通过TreeModel 执行以触发正确的事件(即treeNodesChanged)。 DefaultTreeModel 为此提供了一个实用方法:nodeChanged

但是,JTree 中的工具提示是由 JTree 通过重新调用 TreeCellRenderer 主动处理的,这意味着无需执行任何操作来更改工具提示。每次需要显示工具提示时,都会执行给定节点的渲染。请参阅这个不断更新其工具提示的示例(只需在树的节点周围移动鼠标)。

import java.awt.Component;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;

public class TestTree {

    public class MyTreeCellRenderer extends DefaultTreeCellRenderer {

        private int rendering = 0;

        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row,
                boolean hasFocus) {
            Component cell = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
            if (cell instanceof JComponent) {
                ((JComponent) cell).setToolTipText("Hello " + rendering++);
                if (value instanceof Node && cell instanceof JLabel) {
                    ((JLabel) cell).setText(((Node) value).name);
                }
            }
            return cell;
        }
    }

    private JFrame f;
    private JTree tree;

    protected void initUI() {
        Node root = new Node("Root");
        fillTree(root, 5, "Some tree label");
        DefaultTreeModel model = new DefaultTreeModel(root);

        tree = new JTree(model);
        ToolTipManager.sharedInstance().registerComponent(tree);
        tree.setCellRenderer(new MyTreeCellRenderer());
        f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.add(new JScrollPane(tree));
        f.pack();
        f.setVisible(true);

    }

    public void fillTree(Node parent, int level, String label) {
        for (int i = 0; i < 5; i++) {
            Node node = new Node(label + " " + i);
            parent.addNode(node);
            if (level > 0) {
                fillTree(node, level - 1, label);
            }
        }

    }

    public class Node implements TreeNode {

        private Node parent;
        private List<Node> children;
        private String name;

        public Node(String name) {
            this.name = name;
            this.children = new ArrayList<TestTree.Node>();
        }

        public void addNode(Node child) {
            children.add(child);
            child.parent = this;
        }

        @Override
        public TreeNode getChildAt(int childIndex) {
            return children.get(childIndex);
        }

        @Override
        public int getChildCount() {
            return children.size();
        }

        @Override
        public Node getParent() {
            return parent;
        }

        @Override
        public int getIndex(TreeNode node) {
            return children.indexOf(node);
        }

        @Override
        public boolean getAllowsChildren() {
            return true;
        }

        @Override
        public boolean isLeaf() {
            return children.size() == 0;
        }

        @Override
        public Enumeration<Node> children() {
            return Collections.enumeration(children);
        }

    }

    public static void main(String[] args) {

        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new TestTree().initUI();
            }
        });
    }

}

【讨论】:

    【解决方案2】:

    我做到了!我没有使用扩展的 CellRenderer,而是使用了树的“getTooltipText”方法(我扩展了树)。这样我就能够根据鼠标指针在它上面的对象来控制工具提示的文本。

    @Override
    public String getToolTipText(MouseEvent evt) {
        if (getRowForLocation(evt.getX(), evt.getY()) == -1)
          return null;
        TreePath curPath = getPathForLocation(evt.getX(), evt.getY());
        TreeNode node = (TreeNode)curPath.getLastPathComponent();
        if(something)
            return "Empty";
    
        if(something_else)
            return "Not empty";
    
        return null;
      }
    

    您还需要在工具提示呈现之前告诉工具提示管理器您的树:

    ToolTipManager.sharedInstance().registerComponent(myTree);
    

    【讨论】:

    • 您为什么要覆盖该方法而不是在 TreeCellRenderer 中执行此操作?你有问题吗?尽管这可行,但使用原生 API 和代码并将单元格渲染留在单元格渲染器中总是更简洁。
    • 嗯,这种方法对我来说更有意义。它看起来更清晰(至少对我来说):)
    • 我想知道您在“something”和“something_else”中执行的测试类型;在 JTree 的上下文中,这对他们来说可能更简单。如果您发现它更清楚,我不会对此进行太多争论。我只是对如何以您的方式更清晰而不是在“单元格渲染器”中执行“单元格渲染”感到困惑。
    • 每个节点都是我的自定义节点之一,在“某事”中,我只是获取一些 id 并比较它们。至于“更清晰”的部分 - 我不知道为什么这样对我来说更清晰,也许是因为我是有时使用 Java 的 C# 程序员,这种方法可能更接近我 :) 我完全知道“getTooltip”方法是什么时候调用等等;)
    猜你喜欢
    • 2014-07-31
    • 2019-12-03
    • 2011-07-04
    • 2013-04-07
    • 2011-01-13
    • 1970-01-01
    • 2011-09-03
    • 1970-01-01
    • 2019-07-23
    相关资源
    最近更新 更多