19

since JTree & TreeModel don't provide tooltips straight out-of-the-box, what do you think, what would be the best way to have item-specific tooltips for JTree?

Edit: (Answering my own question afterwards.)

@Zarkonnen: Thanks for the getTooltipText idea.

I found out another (maybe still a bit nicer) way with overriding DefaultTreeCellRenderer and thought to share it:

public class JTreeWithToolTips {
    private static class OwnRenderer extends DefaultTreeCellRenderer {
        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value,
                boolean sel, boolean expanded, boolean leaf, int row,
                boolean hasFocus) {
            setToolTipText("foobar" + row);
            return super.getTreeCellRendererComponent(tree, value, sel,
                    expanded, leaf, row, hasFocus);
        }
    }

    public static void main(String[] args) {
        JTree tree = new JTree(new Object[] { "foo", "bar", "foobar" });
        tree.setCellRenderer(new OwnRenderer());
        ToolTipManager.sharedInstance().registerComponent(tree);

        JFrame frame = new JFrame();
        frame.getContentPane().add(tree);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}
Touko
  • 11,359
  • 16
  • 75
  • 105
  • 6
    Your answer should be in an answer, so people can vote on it. – Michael Myers Nov 07 '08 at 15:28
  • 2
    DefaultTreeCellRenderer#getTreeCellRendererComponent is called a lot and making this too heavyweight can make stuff not work as expected. Like tooltips that should show up, but don't. Overriding JTree#getToolTipText(MouseEvent e) is only called when needed and as such is a much better solution! – NomeN Jul 11 '13 at 16:43
  • When I tried this the tooltip didn't show up. Zarkonnen's answer worked though. – Amber Nov 14 '16 at 22:08

3 Answers3

15

See getTooltipText on JTree. This should allow you to show tooltips depending on what in the tree is being hovered over. (Do read the docs though, you need to register the JTree with the ToolTipManager.)

Amber
  • 2,413
  • 1
  • 15
  • 20
Zarkonnen
  • 22,200
  • 14
  • 65
  • 81
  • 5
    +1 for noting that you need to register with `ToolTipManager`. Even though it's in the docs, it's easy to miss. – Rangi Keen Jun 11 '15 at 19:29
1

Yeah, you can use onMouseMoved and then use a method (I don't remember the name) that tells you in which node you are over. If you get null, obviously then you are not over a node.

Cosmin
  • 21,216
  • 5
  • 45
  • 60
Agustin
  • 69
  • 6
  • 14
  • 1
    Since it's not mentioned elsewhere: the methods linking mouse position to tree node are `getPathForLocation(int, int)` and `getRowForLocation(int, int)`. As suggested by other answers, implementing custom renderer or overriding `getToolTipText(MouseEvent)` is cleaner than adding a `MouseListener`. – Hollis Waite Dec 18 '13 at 13:40
1

When dealing with specific TreeNode subclasses, based on your own answer and comments, I came up with an interface for my TreeNode to implement.

Notice how we check if the value is an intance of Tooltipable in the TreeCellRenderer:

public static interface Tooltipable {
    public String getToolTip();
}

public static class TheNode extends DefaultMutableTreeNode implements Tooltipable {

    private String shortDesc, longDesc;

    public TheNode(String shortDesc, String longDesc) {
        super();
        this.shortDesc = shortDesc;
        this.longDesc = longDesc;
    }

    @Override
    public String getToolTip() {
        return longDesc;
    }

    @Override
    public String toString() {
        return shortDesc;
    }
}

public static class TheModel extends DefaultTreeModel {
    public TheModel() {
        super(new TheNode("Root", "The base of everything"));
        TheNode root = (TheNode)getRoot();
        root.add(new TheNode("Second", "I am a number two"));
        TheNode node = new TheNode("Third", "Another one bites the dust");
        root.add(node);
        node.add(new TheNode("Last", null)); // No tooltip for this one
    }
}

public static class TreeTooltipRenderer extends DefaultTreeCellRenderer {
    @Override
    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
        if (value instanceof Tooltipable)
            setToolTipText(((Tooltipable)value).getToolTip());
        return super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
    }
}

public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setBounds(100, 100, 300, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JTree tree = new JTree(new TheModel());
    ToolTipManager.sharedInstance().registerComponent(tree);
    tree.setCellRenderer(new TreeTooltipRenderer());
    frame.add(new JScrollPane(tree), BorderLayout.CENTER);
    frame.setVisible(true);
}
Matthieu
  • 2,736
  • 4
  • 57
  • 87