更改 Nimbus LaF 处理 JTree 节点突出显示的方式

Posted

技术标签:

【中文标题】更改 Nimbus LaF 处理 JTree 节点突出显示的方式【英文标题】:changing how Nimbus LaF handles JTree node highlighting 【发布时间】:2012-05-07 13:52:50 【问题描述】:

我一直在努力将 Java 应用程序从 WindowsLookAndFeel 转换到 Nimbus,尽管 Nimbus 存在缺陷,但基本上是成功的。我的用户总体上喜欢 Nimbus LaF,但不喜欢某些细节,其中一些我通过咨询本网站上的先前问题进行了更改。示例:我从 Windows LaF(他们喜欢)复制了 LeafIcon、ClosedIcon 和 OpenIcon,并在 Nimbus 版本中使用它们,以获得 LaF 的完美组合。

卡在最后一个 (?) 问题上。

我有一个带有子类 DefaultCellRenderer 的 JTree 来创建适当的节点显示。这在 WindowsLookAndFeel 下运行良好。

问题: 在 WindowsLaF 下,当一个节点被选中时,节点的文本被高亮显示,效果在视觉上很容易理解。在 Nimbus 下,当一个节点被选中时,突出显示是用一个(相当暗)颜色的条来完成的,它运行树窗口的宽度(不仅仅是文本的宽度),效果令人不安。

所以:我只希望在 Nimbus LaF 中突出显示 JTree 节点的 WindowsLaF 处理(即,仅对文本的宽度着色背景,最好是我可以选择的更好的颜色)。我怀疑这意味着我需要将正确的分类 Painter 分配给 “Tree:TreeCell[Focused+Selected].backgroundPainter”,但是不知道怎么写。

欢迎提出建议。


编辑

在 Java 7 中查看奇怪的选定节点突出显示!

public class TreeBorder 
    public static void main( String[] args ) 
        try
            for( UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels() ) 
                if( "Nimbus".equals( info.getName() ) ) 
                    UIManager.setLookAndFeel( info.getClassName() );
                    break;
                
            
         catch( Exception e ) 
            e.printStackTrace();
        
        SwingUtilities.invokeLater( new Runnable() 
            @Override
            public void run() 
                JFrame f = new JFrame();
                f.setLocationRelativeTo( null );
                f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
                f.getContentPane().add( getJTree() );
                f.pack();
                f.setVisible( true );
            
            private JTree getJTree() 
                JTree jTree = new JTree();
                jTree.setCellRenderer( new LocalRenderer() );
                return jTree;
            
         );
    

    private static class LocalRenderer extends DefaultTreeCellRenderer 
        @Override
        public Component getTreeCellRendererComponent( JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasfocus ) 
            DefaultTreeCellRenderer result = (DefaultTreeCellRenderer)super.getTreeCellRendererComponent( tree, value, sel, expanded, leaf, row, hasfocus );
                if( true ) 
                    result.setFont( new JLabel().getFont() );
                    Icon icon = UIManager.getIcon("FileView.floppyDriveIcon");
                    result.setIcon( icon );
                
            return(result);
        
    

【问题讨论】:

我的帖子补充:当然,如果有比画家更简单的方法,那就更好了。尝试将 Tree.selectionBackground 更改为不那么分散注意力的颜色,但 Nimbus 似乎忽略了修改。 进一步我的评论。不能直接设置Tree.selectionBackground,但是这个颜色是从numbusSelectionBackground派生出来的,所以nimbUID.put("nimbusSelectionBackground", new ColorUIResource(205,208,216));产生一些想要的效果(更轻的 Tree.selectionBackground)。仍然突出显示一行而不仅仅是文本,因此仍然会感谢画家的帮助。 @oliholz 请你评论一下你的赏金,我肯定没见过这个问题,因为在大多数情况下,经典的渲染器概念会重载 Nimbus 属性和设置 @mKorbel eee 编辑。使用 DefaultTreeCellRenderer 和 Java7,我在 Nimbus 下得到了令人讨厌的亮点。 Nimbus 错误已在 Java 8 中修复,该修复不再起作用。 【参考方案1】:

编辑

“Tree.selectionBackground”键控制 JTree 上的高亮 - 它是在树级别完成的,而不是在 TreeCellRenderer 级别(这就是为什么管理起来有点混乱)。此代码将为您提供一棵树,您可以在其中控制突出显示:

private JTree getJTree() 

    JTree jTree = new JTree();
    jTree.setOpaque(true);
    jTree.setBackground(Color.white);
    UIDefaults paneDefaults = new UIDefaults();
    paneDefaults.put("Tree.selectionBackground",null);

    JTextPane pane = new JTextPane();
    jTree.putClientProperty("Nimbus.Overrides",paneDefaults);
    jTree.putClientProperty("Nimbus.Overrides.InheritDefaults",false);

    jTree.setCellRenderer( new LocalRenderer() );
    return jTree;

这是一个将突出显示更改为红色的示例。请注意,图标的背景也会突出显示 - 这也是非 nimbus L&F 的默认行为。如果您不想突出显示图标,则必须使用比默认 JLabel 更高级的东西来呈现 TreeCell:

    public Component getTreeCellRendererComponent( JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasfocus ) 
        DefaultTreeCellRenderer result = (DefaultTreeCellRenderer)super.getTreeCellRendererComponent( tree, value, sel, expanded, leaf, row, hasfocus );
        result.setOpaque(true);
            if( true ) 
                result.setFont( new JLabel().getFont() );
                Icon icon = UIManager.getIcon("FileView.floppyDriveIcon");
                result.setIcon( icon );
            
            if(sel)
                result.setBackground(Color.red);
             else
                result.setBackground(Color.white);
            
        return(result);
    

原答案

解决此问题的最简单方法之一是将选定的背景颜色设置为透明。问题是它试图绘制标签的背景——它没有 JTree 选择使用的酷 Nimbus 画家。所以将这一行添加到getTreeCellRendererComponent 方法中:

result.setBackgroundSelectionColor(new Color(0,0,0,0));

另一种选择是使用 Nimbus Painter 作为 TreeCellRenderer 的背景 - 但在这种情况下这似乎有点过头了。

【讨论】:

hmm ...不是真的,因为我理解这个问题是关于防止渲染器的背景着色outside(同时保持它inside)使用不可见的颜色(如果它有任何效果的话)会阻止两者。 @kleopatra 呵呵……也许下次我会阅读完整的问题。很好的收获。 在这里操作;很长一段时间后才重新检查,很高兴看到问题得到了解答,并且有效。非常感谢代码和有关它在树级别处理的信息。 不再适用于 Java 8。但 Nimbus 错误已修复。 又来了。 @oliholz:抱歉,我没有看到 Nimbus 错误已修复。尝试构建一棵微不足道的树;在默认 L&F 和 Numbus 中选择会获得不同的突出显示行为。默认仅突出显示节点的文本,而 Nimbus 突出显示树框架的宽度(这是我最初的问题)。在***.com/questions/28691272/…的最后一个答案中借用了这个想法,并使用了一个简单地淡化颜色的画家,看起来更好。仍然想将突出显示限制为仅节点文本。欢迎提出想法。

以上是关于更改 Nimbus LaF 处理 JTree 节点突出显示的方式的主要内容,如果未能解决你的问题,请参考以下文章

Java程序,JTree获取节点ID

在 Java GUI 中更新 JTree

JTree 通过单击行上的任意位置选择节点

JAVA 得到jtree 某节点下的子节点

JTree的使用(总结,非常简洁)

从 JTree 添加和删除节点