0

There is a method in DefaultTreeCellRenderer called setBackgroundSelectionColor() that allows you to change the selection color when you select an item on a JTree. When I went in the source code of DefaultTreeCellRenderer, the selection color is set in paint() by getBackgroundSelectionColor().

Below in the code, I am attempting to change the selection color by simply overriding the paint method. The problem is that the colors remain the same even when set manually in the paint method. Also the method setBackgroundSelectionColor() still works even though getBackgroundSelectionColor() is no longer used in paint.

Why is this and how can I override the colors correctly?
Without using setBackgroundSelectionColor()

import java.awt.*;

import javax.swing.*;
import javax.swing.tree.*;

@SuppressWarnings("serial")
public class DirectoryExplorer extends JFrame {
    private DirectoryExplorer() {
        super("Directory Explorer");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new GridLayout(1, 1));
        createPanel();
        setSize(800,600);
        setVisible(true);
    }

    private void createPanel() {
        JPanel panel = new JPanel(new GridLayout(1, 1));
        JTree tree = new JTree();

        paintRenderer pR = new paintRenderer();
        tree.setCellRenderer(pR);

        //pR.setBackgroundSelectionColor(Color.RED); //Why does this work when changing value in paint doesn't

        panel.add(new JScrollPane(tree));
        getContentPane().add(panel);
    }

    public static void main(String[] args) {
        new DirectoryExplorer();
    }

    private class paintRenderer extends DefaultTreeCellRenderer {
        @Override
        public void paint(Graphics g) {
            Color bColor;

            if (selected) {
                bColor = Color.RED;//= getBackgroundSelectionColor();
            } else {
                bColor = getBackgroundNonSelectionColor();
                if (bColor == null) {
                    bColor = getBackground();
                }
            }

            //super.paint(g); //Paints the correct colors but no text

            int imageOffset = -1;
            if (bColor != null) {
                imageOffset = getLabelStart();
                g.setColor(bColor);
                if(getComponentOrientation().isLeftToRight()) {
                    g.fillRect(imageOffset, 0, getWidth() - imageOffset, getHeight());
                } else {
                    g.fillRect(0, 0, getWidth() - imageOffset, getHeight());
                }
            }

            if (hasFocus) {
                if (imageOffset == -1) {
                    imageOffset = getLabelStart();
                }

                if(getComponentOrientation().isLeftToRight()) {
                    paintFocus(g, imageOffset, 0, getWidth() - imageOffset, getHeight(), bColor);
                } else {
                    paintFocus(g, 0, 0, getWidth() - imageOffset, getHeight(), bColor);
                }
            }
            super.paint(g); //Paints text but wrong colors
        }

        private void paintFocus(Graphics g, int x, int y, int w, int h, Color notColor) {
            Color bsColor = Color.RED;//= getBorderSelectionColor();

            if (bsColor != null && selected) {
                g.setColor(bsColor);
                g.drawRect(x, y, w - 1, h - 1);
            }
        }

        private int getLabelStart() {
            Icon currentI = getIcon();
            if(currentI != null && getText() != null) {
                return currentI.getIconWidth() + Math.max(0, getIconTextGap() - 1);
            }
            return 0;
        }
    }
}

Edit
What it currently looks like

enter image description here

Dan
  • 5,704
  • 4
  • 31
  • 75

1 Answers1

0

The problem is that you are overriding paint(...) instead of paintComponent(...)

As stated in this answer you should not override paint for something which is not a top level container in swing, instead, you should override paintComponent.

Change the code to look something like this.

@Override
public void paintComponent(Graphics g) {
...
super.paintComponent(g);
}

For example

import java.awt.*;

import javax.swing.*;
import javax.swing.tree.*;

@SuppressWarnings("serial")
public class DirectoryExplorer extends JFrame {
    private DirectoryExplorer() {
        super("Directory Explorer");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new GridLayout(1, 1));
        createPanel();
        setSize(800,600);
        setVisible(true);
    }

    private void createPanel() {
        JPanel panel = new JPanel(new GridLayout(1, 1));
        JTree tree = new JTree();

        paintRenderer pR = new paintRenderer();
        tree.setCellRenderer(pR);

        panel.add(new JScrollPane(tree));
        getContentPane().add(panel);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> new DirectoryExplorer());
    }

    private class paintRenderer extends DefaultTreeCellRenderer {
        @Override
        public void paintComponent(Graphics g) {
            Color bColor;

            if (selected) {
                bColor = Color.RED;
            } else {
                bColor = getBackgroundNonSelectionColor();
                if (bColor == null) {
                    bColor = getBackground();
                }
            }

            int imageOffset = -1;
            if (bColor != null) {
                imageOffset = getLabelStart();
                g.setColor(bColor);
                if(getComponentOrientation().isLeftToRight()) {
                    g.fillRect(imageOffset, 0, getWidth() - imageOffset, getHeight());
                } else {
                    g.fillRect(0, 0, getWidth() - imageOffset, getHeight());
                }
            }

            if (hasFocus) {
                if (imageOffset == -1) {
                    imageOffset = getLabelStart();
                }

                if(getComponentOrientation().isLeftToRight()) {
                    paintFocus(g, imageOffset, 0, getWidth() - imageOffset, getHeight());
                } else {
                    paintFocus(g, 0, 0, getWidth() - imageOffset, getHeight());
                }
            }
            super.paintComponent(g);
        }

        private void paintFocus(Graphics g, int x, int y, int w, int h) {
            Color bsColor = Color.RED;

            if (bsColor != null && selected) {
                g.setColor(bsColor);
                g.drawRect(x, y, w - 1, h - 1);
            }
        }

        private int getLabelStart() {
            Icon currentI = getIcon();
            if(currentI != null && getText() != null) {
                return currentI.getIconWidth() + Math.max(0, getIconTextGap() - 1);
            }
            return 0;
        }
    }
}
Community
  • 1
  • 1
Dan
  • 5,704
  • 4
  • 31
  • 75