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

mKorbel
  • 109,525
  • 20
  • 134
  • 319
haferblues
  • 2,155
  • 4
  • 26
  • 39

2 Answers2

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).
David Kroukamp
  • 36,155
  • 13
  • 81
  • 138
  • Thanks! That worked. Thanks also for the other suggestion, but to save time, I copied the JTree example from here: http://www.apl.jhu.edu/~hall/java/Swing-Tutorial/Swing-Tutorial-JTree.html and just adapted it a bit. So this guy is to blame :-) – haferblues Jan 28 '13 at 14:17
  • @mKorbel any reasoning as to why? I only use the latest java so hard to test – David Kroukamp Jan 28 '13 at 14:21
  • @haferblues Just out of curiosity, have you tried my answer and does it work? – Hui Zheng Jan 28 '13 at 14:22
  • @David Kroukamp no idea, let it be :-) – mKorbel Jan 28 '13 at 14:23
  • @haferblues: On `AquaLookAndFeel`, the UI delegate makes the text white for contrast; you may want to test `Color.*.darker()`, too. – trashgod Jan 28 '13 at 16:34
5

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

Hui Zheng
  • 10,084
  • 2
  • 35
  • 40
  • 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. – haferblues Jan 28 '13 at 13:59
  • 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? – Hui Zheng Jan 28 '13 at 14:03
  • haven't tried it, because I don't like setting properties via UIManager. David's solution seems to be the right for this case. – haferblues Jan 29 '13 at 15:20
  • It will completely disable any background, such as a different color when an item is selected, which may be undesirable. – Raketenolli Dec 20 '18 at 10:43