如何正确地为JTree和所有节点着色

时间:2012-07-14 10:46:32

标签: java swing

让我解释一下我需要什么以及我来得多远:

我有一个JTree带有自定义模型和一些漂亮的图标,一切正常,但是,树的默认颜色(白色)不适合我试图设计的GUI我希望能够改变它的背景颜色。

这已被证明是一件苦差事!

我已经在网络上看到了很多这方面的解释,它们似乎围绕扩展DefaultTreeCellRendererBasicTreeUI,但有一些暗示这些都是黑客,应该避免,虽然没有解释为什么他们是黑客或应该做什么。

在任何情况下,建议的方法似乎都不能很好地工作,因为我总是最终得到两种情况之一:

颜色在树中设置,但树标签的末尾和树的右侧之间,标签和它们的图标之间以及用于展开树的正/负小部件之间存在令人讨厌的间隙。在这种情况下,建议实施完整的行选择。

另一个场景已经实现了完整的行选择,并且节点正确着色并且完整行选择有效,但是图标要么完全丢失,要么加/减小部件,或者两者都有一个令人讨厌的白色边框。 / p>

我自己的尝试失败了,我现在留下了以下代码,它为树和节点着色,但仍然在树标签的末尾和所有图标之间留下令人讨厌的白色边框。

final Color MainBg = new Color(213,220,228);
KTree.setCellRenderer(new DefaultTreeCellRenderer()
{
    @Override
    public Component getTreeCellRendererComponent(JTree pTree, Object pValue, boolean pIsSelected, boolean pIsExpanded, boolean pIsLeaf, int pRow, boolean pHasFocus)
    {
            super.getTreeCellRendererComponent(pTree, pValue, pIsSelected, pIsExpanded, pIsLeaf, pRow, pHasFocus);
            setBackgroundNonSelectionColor(MainBg);
            setBackgroundSelectionColor(MainBg);
            setTextNonSelectionColor(Color.BLACK);
            setTextSelectionColor(Color.BLACK);
            ImageIcon tDoc = createImageIcon("images"  + File.separator + "document.gif","document");
            ImageIcon tOpen = createImageIcon("images"  + File.separator + "book_open.gif","book open");
            ImageIcon tClosed = createImageIcon("images"  + File.separator + "bookclosed.png","book closed");
            setClosedIcon(tClosed);
            setOpenIcon(tOpen);
            setLeafIcon(tDoc);
            putClientProperty("Tree.collapsedIcon", tDoc);
            putClientProperty("tree.expandedIcon", tOpen);
        return (this);
    }
});

我的问题:

1)当然,我很感激帮助获得JTree上的颜色设置,我很乐意接受建议,但如果您打算发布链接,我很有可能已经在那里在过去的几天里,还有......

2)我很欣赏对该过程所涉及的确切解释。我阅读了很多关于JTree的教程,但没有关注完全着色树的问题(如果有的话),这就是我正在寻找的,似乎有一些关于究竟是什么的讨论必需的,例如是否完整行选择,是否继承子类等等。

我还想了解为什么某些事情被认为是' hacks'什么是替代品。


编辑 - 解决方案

我正在添加这一部分,以显示我在整理过程中取得的进展,并且可能让其他人在一个相当繁琐的过程中先行一点。我花了好几天试图让这个系统与L& F系统正常工作,我已经圈了几次。毫无疑问,这很大程度上取决于缺乏经验,所以如果这样可以节省其他人一些头发拉动会话,那就更好了!

顺便说一句:如果我做了一些被认为是黑客的事情,我会非常高兴听到批评,但请提供一个(工作)替代方案和一些明确的推理背后的标签。

好吧,让我们开始吧:我想设置系统L& F因为我不喜欢其他选项,因为我喜欢用户看到一个与他们习惯的东西相匹配的程序。在我做其他事情之前,我将L& F设置为这样:

try
    {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    }
catch (Exception e) { return; }

这会将JTree设置为您正在使用的操作系统的标准。这似乎包括设置树本身的背景,以及节点选择的背景等。如果你想要的只是标准的JTree,你就可以开始了,但是当我想看到基于系统的滚动条等时,我也希望看到背景以外的颜色而不是白色。

我将背景设置为一个漂亮的蓝色(请注意,颜色会在一瞬间再次使用,因此final声明):

final Color MainBg = new Color(213,220,228);
    KTree.setBackground(MainBg);

我现在拥有的是具有漂亮蓝色背景的JTree,其仅覆盖不包含节点的树的那些区域,其根据L& F的设置保持白色。我现在需要为节点本身设置一些颜色,为此我需要使用以下代码覆盖getTreeCellRendererComponent的{​​{1}}:

DefaultTreeCellRenderer

以上是 createImageIcon 。这直接来自一个教程,但请注意,这是在我完成之前编辑的(所以不要复制并粘贴代码!):

final Color SellBg = new Color(232,235,237);
final Color HiliBg = new Color(150,196,246);

KTree.setCellRenderer(new DefaultTreeCellRenderer()
{

    @Override
    public Component getTreeCellRendererComponent( JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus)
    {
        super.getTreeCellRendererComponent( tree, value, sel, expanded, leaf, row, hasFocus);
        setBackgroundNonSelectionColor(MainBg);
        setBackgroundSelectionColor(SellBg);
        setTextNonSelectionColor(Color.BLACK);
        setTextSelectionColor(Color.BLACK);
        ImageIcon tDoc = createImageIcon("images"  + File.separator + "document.gif","document");
        ImageIcon tOpen = createImageIcon("images"  + File.separator + "book_open.gif","open");
        ImageIcon tClosed = createImageIcon("images"  + File.separator + "bookclosed.png","closed");
        setClosedIcon(tClosed);
        setOpenIcon(tOpen);
        setLeafIcon(tDoc);
        setBorderSelectionColor(HiliBg);
        return this;
    }
});

如果您正在关注代码,那么在此阶段您将看到我为树节点设置了各种颜色,并为它们添加了一些图标。所有这一切都很好,但是现在节点文本的末端和protected ImageIcon createImageIcon(String path, String description) { java.net.URL imgURL = getClass().getResource(path); if (imgURL != null) { return new ImageIcon(imgURL, description); } else { System.err.println("Couldn't find file: " + path); return null; } } 本身的边缘之间以及节点文本和图标之间以及树的正/负小部件之间存在令人讨厌的白色块。 。这些白色块在扩展时也会穿过树。

这就是我进来的地方,头发拉开了。感谢Jacob'建议和MadProgrammer'提示(谢谢你们)我在正确的轨道上,但这是事情变得奇怪的地方,很可能是因为我已经在忙着用JTree来试图让事情发挥作用。将代码回滚到以前的版本并再次启动此部分有助于使工作正常运行。

快速注意:如果我以错误的方式做这件事,请告诉我!

似乎要更改JTree的白色部分,我需要覆盖JTree,我这样做了:

BasicTreeUI

我必须声明这不是我的代码 - 我在众多教程网站中的一个上找到了它,它按照建议工作,我的KTree.setUI(new javax.swing.plaf.basic.BasicTreeUI() { @Override public Rectangle getPathBounds(JTree tree, TreePath path) { if(tree != null && treeState != null) { return getPathBounds(path, tree.getInsets(), new Rectangle()); } return null; } private Rectangle getPathBounds(TreePath path, Insets insets, Rectangle bounds) { bounds = treeState.getBounds(path, bounds); if(bounds != null) { bounds.width = tree.getWidth(); bounds.y += insets.top; } return bounds; } }); 现在有正确的背景,但是,加/减小部件有disapeared!

很可能有一种简单的方法可以在上面的代码中设置这些小部件,但是我注意到雅各布关于弄乱JTree的警告,所以我直接放置了以下代码 之后我设置了L& F:

BasicTreeUI

这会将加/减小部件图标设置为我自己的一些,并在树中的元素之间设置我想要的画线类型。请注意,此时我收到错误,因为无法访问之前的非静态 createImageIcon 。我必须编辑这样的代码以允许同时调用此方法:

ImageIcon clapsed = createImageIcon("images"  + File.separator + "plus.gif","closed");
ImageIcon clopen = createImageIcon("images"  + File.separator + "minus.gif","open");
UIManager.getLookAndFeelDefaults().put("Tree.collapsedIcon",clapsed);
UIManager.getLookAndFeelDefaults().put("Tree.expandedIcon",clopen);
UIManager.getLookAndFeelDefaults().put("Tree.paintLines", true);
UIManager.getLookAndFeelDefaults().put("Tree.leftChildIndent",7);
UIManager.getLookAndFeelDefaults().put("Tree.lineTypeDashed",true)

我现在(终于!)有一个protected static ImageIcon createImageIcon(String path, String description) { Class<?> cl=new Object(){}.getClass().getEnclosingClass(); java.net.URL imgURL = cl.getResource(path); if (imgURL != null) { return new ImageIcon(imgURL, description); } else { System.err.println("Couldn't find file: " + path); return null; } } ,系统L&amp; F设置,并为树的所有元素设置颜色。

仍有未解决的问题:

我(还)没有完全理解JTree代码 - 这给了我我需要的颜色,但似乎也给了我全行选择。但是我无法让选择颜色跨越整个距离。我打算稍后再玩这个,但是我要谨慎,感谢Jacob&#39;警告 - 如果有人对此有任何严格的规定,我会非常乐意听到这些规则。

我还故意设置L&amp; F,以便用户可以看到他们熟悉的东西,尽管颜色不同。但是,我被迫将自己的图标添加到加/减树小部件,这不是一个真正的问题,而是一个小小的问题。这可能会在以后清理。

我的另一个问题是,当使用BasicTreeUI()设置值时,我只能设置某些键,其他键显然会被忽略。 MadProgrammer确实指出使用Nimbus可能会使这些键混乱一点,所以也许使用L&amp; F系统有它自己的怪癖。

无论如何,这是我努力的结果。我为这篇文章的篇幅道歉,但我希望这可以帮助别人,如果我以错误的方式做了某些事情,那么有人可以向我指出正确的方法。< / p>

此致

MVK

2 个答案:

答案 0 :(得分:3)

如果您已经覆盖getTreeCellRendererComponent以便树项具有您想要的颜色,则可以使用

UIManager.getLookAndFeelDefaults().put("Tree.background", new ColorUIResource(aColor);

更改树中“未占用”空间的颜色。请注意,这将影响所有未来树。组件UI类使用此属性,许多人在绘制组件时都喜欢它。要找出存在哪些键,您可以执行以下操作:

for (Entry<Object, Object> entry : UIManager.getLookAndFeelDefaults().entrySet()) {
    System.out.println(entry.getKey() + " : " + entry.getValue());
}

至于你的其他问题,我永远不会考虑将getTreeCellRendererComponent覆盖为黑客,但不小心延伸BasicTreeUI可能会导致某些外观出现意外行为。

答案 1 :(得分:0)

如果您正在寻找的是一种在JTree中同时拥有系统L&amp; F和彩色背景+文本的方法,那么这就是您需要的所有代码:

        try {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        UIManager.getLookAndFeelDefaults().put("Tree.background", new ColorUIResource(Util.BACKGROUND));
        UIManager.getLookAndFeelDefaults().put("Tree.textBackground", new ColorUIResource(Util.BACKGROUND));
    } catch (ClassNotFoundException | InstantiationException
            | IllegalAccessException | UnsupportedLookAndFeelException e) {
        e.printStackTrace();
    }