JTree设置节点背景为非不透明

9
请查看 SSCCE。我该如何使未选择的树节点背景透明?目前未选择节点的背景是白色的。但是,如果未选择(并且当选中时为绿色),我的单元格渲染器应该将其非不透明。最终,我希望未选择的节点只是没有背景的文本,因为在我的应用程序中,SSCCE 中红色区域有渐变填充。
    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

2个回答

18

你应该覆盖 getBackgroundNonSelectionColorgetBackgroundSelectionColor 以及 getBackground 方法,并返回适当的值,如下所示:

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

这将产生:

图片描述

其他建议:

  • 事件分发线程上创建和操作Swing组件。
  • 不要不必要地扩展JFrame,而是创建一个实例并使用它。
  • 不要在JFrame上调用setSize,而是使用正确的LayoutManager和/或重写getPreferredSize(),并在添加所有组件后,在将其设置为可见之前调用pack()JFrame上。
  • 记得使用DISPOSE_ON_CLOSEEXIT_ON_CLOSE调用JFrame#setDefaultCloseOperation(通常优先使用DISPOSE_XXX,除非使用Timer,因为这样可以允许main(String[] args)在Gui关闭后继续执行)。

谢谢!那个方法可行。也感谢你的其他建议,但为了节省时间,我从这里复制了JTree示例:http://www.apl.jhu.edu/~hall/java/Swing-Tutorial/Swing-Tutorial-JTree.html 然后稍作修改。所以这个家伙应该为此负责 :-) - haferblues
@mKorbel 有什么理由吗?我只使用最新的Java,所以很难测试。 - David Kroukamp
@haferblues 只是出于好奇,你尝试了我的答案并且它起作用了吗? - Hui Zheng
@David Kroukamp 没有想法,就让它这样吧 :-) - mKorbel
@haferblues:在AquaLookAndFeel中,UI代理使文本变为白色以增加对比度;您可能还想测试Color.*.darker() - trashgod

5
为了避免背景填充,只需在new SimpleTree();之前或在super("Creating a Simple JTree");之后加入UIManager.put("Tree.rendererFillBackground", false);

我添加了一张截图。我想要节点文本没有白色背景。相反,它应该是透明的,这样节点文本就只会绘制在内容面板的红色背景上。在渲染器中将背景设置为new Color(0,0,0)并没有起到帮助作用。 - haferblues
你试过我的解决方案吗?我运行了你的程序,并在我的答案中添加了UIManager.put("Tree.rendererFillBackground", false);,现在节点文本具有透明背景。这是你所需要的吗? - Hui Zheng
我还没有尝试过,因为我不喜欢通过UIManager设置属性。David的解决方案似乎是这种情况下的正确选择。 - haferblues
它将完全禁用任何背景,例如在选择项目时出现的不同颜色,这可能是不可取的。 - Raketenolli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接