让我解释一下我需要什么以及我已经走了多远:
我有JTree
一个自定义模型和一些漂亮的图标,一切正常,但是,树的默认颜色(白色)不适合我正在尝试设计的 GUI,我希望能够更改其背景颜色。
事实证明,这很麻烦!
我在网上看到了很多对此的解释,它们似乎围绕着扩展 theDefaultTreeCellRenderer
或应该改为。BasicTreeUI
无论如何,建议的方法似乎都不是很好,因为我总是遇到以下两种情况之一:
颜色是在树中设置的,但是在树标签的末端和树的右侧之间、标签和它们的图标之间以及用于扩展树的加/减小部件之间存在令人讨厌的间隙。在这种情况下,建议实施全行选择。
另一种情况是实现了全行选择,节点颜色正确,全行选择有效,但图标或者完全丢失,连同加/减小部件,或者两者周围仍然存在令人讨厌的白色边框。
我自己的尝试失败了,我目前只剩下以下代码,它为树和节点着色,但仍然在树标签的末尾和所有图标之间留下令人讨厌的白色边框。
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
但没有长期关注的教程(如果有的话)完全着色一棵树的问题,这是我正在寻找的,并且似乎有一些关于确切需要什么的讨论,例如完整行选择与否,子类化与否等。
我还想了解为什么某些事情被认为是“黑客”以及替代方案是什么。
编辑 - 一个解决方案
我添加这一部分是为了展示我在解决这个问题方面取得的进展,并可能让其他人在这个相当繁琐的过程中领先一步。我花了几天的时间试图让它与 System L&F 一起正常工作,我已经转了好几次了。毫无疑问,这很大程度上是由于缺乏经验,所以如果这可以为其他人节省一些拉头发的时间,那就更好了!
顺便说一句:如果我做了一些被认为是 hack 的事情,我很乐意听到批评,但请提供一个(可行的)替代方案以及 Hack 标签背后的一些明确推理。
好的,让我们开始吧:我想要设置系统 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
of :DefaultTreeCellRenderer
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;
}
});
这是上面的createImageIcon。这直接来自教程,但请注意,这是在我完成之前编辑的(所以不要复制和粘贴此代码!):
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;
}
}
如果您遵循代码,那么在此阶段您将看到我为树节点设置了各种颜色,并为它们添加了一些图标。所有这一切都很好,但是现在在节点文本的末端和JTree
自身的边缘之间,以及节点文本和图标之间,以及树的加/减小部件之间都有令人讨厌的白色块。随着树的扩展,这些白色块也会穿过树。
这几乎就是我进来的地方,开始拉头发。多亏了 Jacob 的建议和 MadProgrammer 的提示(谢谢大家),我走在了正确的轨道上,但这就是事情变得奇怪的地方,很可能是因为我已经在搞砸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;
}
});
我必须声明这不是我的代码 - 我在许多教程网站之一上找到了它,它按照建议工作,我JTree
现在有一个正确绘制的背景,但是,加号/减号小部件已经消失了!
很可能有一种简单的方法可以从上面的代码中设置这些小部件,但是我注意到 Jacob 关于弄乱的警告,所以我在设置 L&F 后直接BasicTreeUI
放置了以下代码:
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)
这会将加/减小部件图标设置为我自己的一些图标,并在树中的元素之间设置我想要的绘制线条的类型。请注意,此时我收到一个错误,因为无法访问之前的非静态createImageIcon 。我必须像这样编辑代码以允许调用此方法:
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;
}
}
我现在(终于!)有一个JTree
, 设置了系统 L&F,并为树的所有元素设置了颜色。
仍然存在未解决的问题:
我(尚未)完全理解BasicTreeUI()
代码 - 这给了我所需的颜色,但似乎也给了我完整的行选择。但是我一直无法让选择颜色跨越整个距离。我打算稍后再玩,但感谢 Jacob 的警告,我会保持谨慎 - 如果有人对此有任何硬性规定,我很乐意听到。
我还特意设置了 L&F,以便用户可以看到他们熟悉的东西,尽管颜色不同。但是,我被迫将自己的图标添加到加/减树小部件中,这并不是真正的问题,而是有点小问题。这很可能在以后得到澄清。
我的另一个担忧是,当使用我设置值时,UIManager
我只能设置某些键,而其他键显然被忽略了。MadProgrammer 确实指出使用 Nimbus 可能会使这些键有些混乱,因此使用 L&F 系统可能有其自身的怪癖。
不管怎样,这是我目前努力的结果。我为这篇文章的长度道歉,但我希望这可以帮助其他人,并且如果我以错误的方式做某事,有人可以向我指出正确的解决方法。
问候
MVK