Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

changing how Nimbus LaF handles JTree node highlighting

I have been working to transition a Java application from WindowsLookAndFeel to Nimbus, largely successfully, despite Nimbus foibles. My users overall like the Nimbus LaF but didn't like some details, some of which I changed by consulting previous questions on this site. Example: I copied the LeafIcon, ClosedIcon and OpenIcon from Windows LaF (which they liked) and use them in the Nimbus version, for a nice combination of LaFs.

Stuck on one last (?) problem.

I have a JTree with a subclassed DefaultCellRenderer to create the appropriate node displays. This works fine under WindowsLookAndFeel.

Problem: Under WindowsLaF when a node is selected the text of the node is highlighted, and the effect is visually easy to understand. Under Nimbus when a node is selected the highlighting is done with a bar of (fairly dark) color that runs the width of the tree window (not just the width of the text), and the effect is disconcerting.

So: I simply want WindowsLaF treatment of JTree node highlighting in the Nimbus LaF (ie colored background only the width of the text, and preferably in a better color that I can choose). I suspect this means I need to assign the right sort Painter to "Tree:TreeCell[Focused+Selected].backgroundPainter", but I don't know how to write it.

Suggestions most welcome.


EDIT

See the strange selected node highlight with Java 7!

enter image description here

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);
        }
    }
}
like image 962
user1359010 Avatar asked Apr 26 '12 19:04

user1359010


1 Answers

Edit

The "Tree.selectionBackground" key is what controls the highlight on the JTree - it's done on the tree level, not on the TreeCellRenderer level (which is why it's a little confusing to manage). This code will get you a Tree where you can control the highlighting:

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

And here's an example of changing the highlighting to Red. Please note that the Icon's background will be highlighted too - this is the default behavior for non-nimbus L&F too. If you don't want the icon to be highlighted, you're going to have to use something fancier than the default JLabel to render the 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);
    }

Original Answer

One of the easiest ways to fix this is to set the selected background color to transparent. The problem is that it's trying to paint the background of the label - which doesn't have the cool Nimbus painter used by the JTree's selection. So add this line to getTreeCellRendererComponent method:

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

Another option is to use the nimbus painter for the background of the TreeCellRenderer - but that seems like overkill in this situation.

like image 178
Nick Rippe Avatar answered Nov 09 '22 15:11

Nick Rippe