JTree node's changable tooltip

2019-07-05 13:08发布

I have a JTree populated with some (custom) nodes. I have a class that's subclass of DefaultTreeCellRenderer and using that "MyTreeCellRenderer" i can set tooltips for each node in my tree. It works fine: JTree is populated, cell renderer is set, all added nodes do have tooltips. Problem is that i don't know how to change tooltip for certain node in already populated tree... How to do that? Is there any way to "recreate" cell renderer for just one node in JTree?

2条回答
你好瞎i
2楼-- · 2019-07-05 13:36

From what I understand of your question, you want to trigger the rendering of a specific node in the Tree. This should be performed through the TreeModel to fire the proper event (ie, treeNodesChanged). The DefaultTreeModel offers a utility method for that purpose: nodeChanged .

However, tooltips in JTree are handled pro-actively by the JTree by reinvoking the TreeCellRenderer, meaning that nothing must be done for the tooltip to be changed. Every time the tooltip needs to be displayed, the rendering for the given node is performed. See this example that continuously updates its tooltip (simply by moving the mouse around the nodes of the tree).

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();
            }
        });
    }

}
查看更多
相关推荐>>
3楼-- · 2019-07-05 13:43

I did it! Instead of using extended CellRenderer i used "getTooltipText" method of tree (i extended the tree). That way i was able to control text of tooltip according to object that has mouse pointer over it.

@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;
  }

You will also need to tell the tooltip manager about your tree before the tooltips will render:

ToolTipManager.sharedInstance().registerComponent(myTree);
查看更多
登录 后发表回答