Paul Reiners
Paul Reiners

Reputation: 7894

Color of the dropdown control and border in an uneditable JComboBox

The background color of the selected item in an uneditable JComboBox is a sort of blue:

alt text

I know that you can change it to a different color, such as white, for example with the following code:

jComboBox1.setRenderer(new DefaultListCellRenderer() {
    @Override
    public void paint(Graphics g) {
        setBackground(Color.WHITE);
        setForeground(Color.BLACK);
        super.paint(g);
    }
});

That gives you something like this:

alt text

However, if you double-click on that combo-box, some of it turns gray (the part with the triangle and the border):

alt text

Is there a way to stop these parts from turning gray when you double-click on it?

Note that, if you call super.paint() first, the whole thing turns dark (including the part behind "Select..."), so that doesn't help.

Upvotes: 4

Views: 5550

Answers (4)

JackHammer
JackHammer

Reputation: 458

Not sure what exactly OP is trying to achieve, but here is my JComboBox coloring recipe:

static public void main(String[] args) {
    JFrame window = new JFrame("Coloring ComboBox");
    window.setSize(170, 150);
    window.setLocationRelativeTo(null);
    window.setLayout(null);
    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    //---textArea is just for focus switching
    JTextArea textArea = new JTextArea();
    textArea.setBounds(5, 5, 140, 25);
    window.add(textArea);

    UIManager.put("ComboBox.selectionBackground", Color.magenta); //---focused background color
    //---see comboBox's UIDefaults for more tweaks

    JComboBox<String> coloredCombo = new JComboBox<String>(new String[]{"Dog", "Cat", "Bird"});
    coloredCombo.setEditable(false);
    coloredCombo.setUI(new BasicComboBoxUI() {
            @SuppressWarnings({"serial"})
            @Override
            protected ComboPopup createPopup() {
                return new BasicComboPopup(coloredCombo) {
                    {
                        //---style popup anyway you like
                        this.setBorder(BorderFactory.createLineBorder(Color.green, 2));//---popup's border color
                    }
                };
            }
            @Override
            protected JButton createArrowButton() {
                //---style arrow button anyway you like
                JButton result = new JButton();
                result.setBackground(Color.orange);//---button's color
                return result;
            }
        });

    coloredCombo.setBorder(BorderFactory.createLineBorder(Color.red, 2));//---border color
    coloredCombo.setBackground(Color.yellow); //---not focused background color

    coloredCombo.setRenderer(new ListCellRenderer<String>() {
        @Override
        public Component getListCellRendererComponent(JList<? extends String> list, String value, int index,
                boolean isSelected, boolean cellHasFocus) {
            JLabel result = new JLabel(value);
            result.setOpaque(true);
            result.setBackground(isSelected ? Color.cyan : Color.blue); //---item background color
            return result;
        }
    });
    coloredCombo.setBounds(5, 35, 140, 25);
    window.add(coloredCombo);

    window.setVisible(true);
}

Of course, this is just an axample, I recommend you to create a fancy custom class to reuse.enter image description here

Upvotes: 3

Devon_C_Miller
Devon_C_Miller

Reputation: 16528

The swing code that calls getListCellRendererComponent, then calls setForeground and setBackground on the returned component (depending on the whether the component is selected and/or focused). I assume this is for some legacy behavior. Unfortunately, it defeats the purpose of my setting it in the renderer.

I've had some good results with this approach:

The code below circumvents changing the foreground and background by overriding the fg/bg setters to do nothing, then I just call the super implementations to set the colors I want.

public static class CustomRenderer extends DefaultListCellRenderer {
    public Component getListCellRendererComponent(JList list, Object value,
        int index, boolean isSelected, boolean cellHasFocus) {
        super.getListCellRendererComponent(list, value, index, isSelected,
            cellHasFocus);
        super.setBackground(Color.WHITE);
        super.setForeground(Color.BLACK);     
        return this;
    }
    public void setForeground(Color c) {}
    public void setBackground(Color c) {}
}

Addendum: The grey border is probably just that, a border. Try the same approach, but also override setBorder.

Upvotes: 0

wolfcastle
wolfcastle

Reputation: 5930

A couple things:

  1. The appearance of the combobox (the display area, the arrow, the drop down) are LAF dependent. Your screen shots suggest WinXP. If you must support any other LAFs, be sure to test that as well, because what works for one LAF may not work for another. I have found this to be particularly true for JComboBoxes.

  2. Like Twister suggests, changing the color by overriding the paint() method likely isn't the best way to do this. Just set the background/foreground color of the combobox itself. If you want to change the color of the dropdown itself (I'm not clear if you want to do this or not), then add a custom renderer that overrides getListCellRendererComponent to set the background/foreground.

    public static class CustomRenderer extends DefaultListCellRenderer {
    
    @Override
    public Component getListCellRendererComponent(JList list, Object value,
            int index, boolean isSelected, boolean cellHasFocus) {
        super.getListCellRendererComponent(list, value, index, isSelected,
                cellHasFocus);
        setBackground(Color.WHITE);
        setForeground(Color.BLACK);     
        return this;
    }       
    

    }

  3. The appearance of the grey triangle and border is because the combo box now has focus. You can just make it not focusable, and the coloring will go away. This may not be the behavior you want, however.

    JComboBox combo = new JComboBox(new Object[]{"Dog", "Cat", "Bird"});
    combo.setBackground(Color.WHITE);
    combo.setForeground(Color.BLACK);
    combo.setFocusable(false);
    

Upvotes: 1

Twister
Twister

Reputation: 724

First, you should not set the foreground and background in the paint method. You should override the getListCellRendererComponent of your renderer in order to customize it. The default renderer change its aspect if you it has the focus or if it is selected. If you do not want those features reimplements the method.

Then if you add a line border to your renderer (setBorder(BorderFactory.createLineBorder(Color.black)) you will see that what is drawn is not part of your renderer but the combobox itself. So you might have to customize the UI

Upvotes: 0

Related Questions