JTree set background of node to non-opaque
Asked Answered
B

2

9

Please have a look at the SSCCE. How can I make the non-selected tree nodes' background transparent. At the moment the background of non-selected nodes is white. My cell renderer, however, should paint it non-opaque if it is not selected (and green when selected...what it does). In the end I want non-selected nodes to be just text without background, since the area which is red in the SSCCE has a gradient fill in my application.

    import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;

public class SimpleTree extends JFrame
{
    public static void main(final String[] args)
    {
        new SimpleTree();
    }

    public SimpleTree()
    {
        super("Creating a Simple JTree");
        final Container content = this.getContentPane();
        content.setBackground(Color.RED);
        final Object[] hierarchy = { "javax.swing", "javax.swing.border", "javax.swing.colorchooser", "javax.swing.event", "javax.swing.filechooser", new Object[] { "javax.swing.plaf", "javax.swing.plaf.basic", "javax.swing.plaf.metal", "javax.swing.plaf.multi" }, "javax.swing.table",
                        new Object[] { "javax.swing.text", new Object[] { "javax.swing.text.html", "javax.swing.text.html.parser" }, "javax.swing.text.rtf" }, "javax.swing.tree", "javax.swing.undo" };
        final DefaultMutableTreeNode root = this.processHierarchy(hierarchy);
        final JTree tree = new JTree(root);
        tree.setOpaque(false);
        tree.setCellRenderer(new MyCellRenderer());
        final JScrollPane scroller = new JScrollPane(tree);
        scroller.getViewport().setOpaque(false);
        scroller.setOpaque(false);
        content.add(scroller, BorderLayout.CENTER);
        this.setSize(275, 300);
        this.setVisible(true);
    }

    /**
     * Small routine that will make node out of the first entry in the array,
     * then make nodes out of subsequent entries and make them child nodes of
     * the first one. The process is repeated recursively for entries that are
     * arrays.
     */

    private DefaultMutableTreeNode processHierarchy(final Object[] hierarchy)
    {
        final DefaultMutableTreeNode node = new DefaultMutableTreeNode(hierarchy[0]);
        DefaultMutableTreeNode child;
        for (int i = 1; i < hierarchy.length; i++)
        {
            final Object nodeSpecifier = hierarchy[i];
            if (nodeSpecifier instanceof Object[]) // Ie node with children
                child = this.processHierarchy((Object[]) nodeSpecifier);
            else
                child = new DefaultMutableTreeNode(nodeSpecifier); // Ie Leaf
            node.add(child);
        }
        return (node);
    }

    public class MyCellRenderer extends DefaultTreeCellRenderer
    {
        @Override
        public Component getTreeCellRendererComponent(final JTree tree, final Object value, final boolean sel, final boolean expanded, final boolean leaf, final int row, final boolean hasFocus)
        {
            final Component ret = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);

            final DefaultMutableTreeNode node = ((DefaultMutableTreeNode) (value));

            this.setText(value.toString());
            if (sel)
            {
                this.setOpaque(true);
                this.setBackground(Color.GREEN);

            }
            else
            {
                this.setOpaque(false);
                this.setBackground(null);
            }
            return ret;
        }
    }
}

enter image description here

Bombsight answered 28/1, 2013 at 13:47 Comment(0)
F
18

You should override getBackgroundNonSelectionColor,getBackgroundSelectionColor and getBackground of DefaultTreeCellRenderer and return appropriate values like so:

public class MyCellRenderer extends DefaultTreeCellRenderer {

    @Override
    public Color getBackgroundNonSelectionColor() {
        return (null);
    }

    @Override
    public Color getBackgroundSelectionColor() {
        return Color.GREEN;
    }

    @Override
    public Color getBackground() {
        return (null);
    }

    @Override
    public Component getTreeCellRendererComponent(final JTree tree, final Object value, final boolean sel, final boolean expanded, final boolean leaf, final int row, final boolean hasFocus) {
        final Component ret = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);

        final DefaultMutableTreeNode node = ((DefaultMutableTreeNode) (value));
        this.setText(value.toString());
        return ret;
    }
}

which will produce:

enter image description here

Other suggestions:

  • Create and manipulate Swing components on Event Dispatch Thread.
  • Dont extend JFrame unnecessarily rather create an instance and use that.
  • Dont call setSize on JFrame rather use a correct LayoutManager and/or override getPreferredSize() and call pack() on JFrame before setting it visible but after adding all components.
  • Remember to call JFrame#setDefaultCloseOperation with either DISPOSE_ON_CLOSE or EXIT_ON_CLOSE (DISPOSE_XXX is usually preferred unless using Timers as this will allow main(String[] args) to continue its execution after Gui has been closed).
Fitts answered 28/1, 2013 at 14:5 Comment(5)
Thanks! That worked. Thanks also for the other suggestion, but to save time, I copied the JTree example from here: apl.jhu.edu/~hall/java/Swing-Tutorial/Swing-Tutorial-JTree.html and just adapted it a bit. So this guy is to blame :-)Bombsight
@mKorbel any reasoning as to why? I only use the latest java so hard to testFitts
@Bombsight Just out of curiosity, have you tried my answer and does it work?Roberto
@David Kroukamp no idea, let it be :-)Meagher
@haferblues: On AquaLookAndFeel, the UI delegate makes the text white for contrast; you may want to test Color.*.darker(), too.Roath
R
5

To avoid background refilling, just put UIManager.put("Tree.rendererFillBackground", false); before new SimpleTree(); or after super("Creating a Simple JTree");.

Roberto answered 28/1, 2013 at 13:57 Comment(4)
I added a screenshot. I want the nodes' text without the white background. Instead of white it should be transparent, so the nodes' text ist just painted on the red background of the content pane. setting the background to new Color(0,0,0) in the renderer didn't help.Bombsight
Have you tried my solution? I did run your program, and after adding UIManager.put("Tree.rendererFillBackground", false); as in my answer, now the nodes' text have transparent background. Is that what you need?Roberto
haven't tried it, because I don't like setting properties via UIManager. David's solution seems to be the right for this case.Bombsight
It will completely disable any background, such as a different color when an item is selected, which may be undesirable.Caspian

© 2022 - 2024 — McMap. All rights reserved.