Better readability/contrast in a disabled JComboBox
Asked Answered
M

5

10

I have a JComboBox that needs to be disabled at some point, but I am feeling that the disabled status makes it quite harder to read because the low contrast it has.

It would be nice if only the drop-down arrow button would be shown as disabled, while keeping the box renderer as if it were enabled.

Actual: actual combo Desired: desired result

Is there an easy way to achieve this or something similar?

Thanks!

Maffei answered 28/1, 2011 at 11:20 Comment(0)
M
7

I've ended up peeking the BasicComboBoxUI, where I've found this:

        if ( comboBox.isEnabled() ) {
            c.setForeground(comboBox.getForeground());
            c.setBackground(comboBox.getBackground());
        }
        else {
            c.setForeground(DefaultLookup.getColor(
                     comboBox, this, "ComboBox.disabledForeground", null));
            c.setBackground(DefaultLookup.getColor(
                     comboBox, this, "ComboBox.disabledBackground", null));
        }

So I've used as renderer component a JLabel with the setForeground method overriden to do nothing. Thus, the colour is never changed and keeps the default black value.

The problem is that this trick is implementation specific. A given Look&Feel or UI Manager might do other things like overpainting with a semi-transparent layer to display disabled items instead of changing the component's colours :-(

Maybe a test could at least give a warning if the installed L&F or UI Manager does not call the setForeground method.

Maffei answered 28/1, 2011 at 12:2 Comment(0)
N
7

Here is another option you have:

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

You will just need to add this code after the instantiation. The letters will always stay black. The combo box frame will turn to be either gray or black if you disable or enable.

They look like this:

enter image description here

Nguyetni answered 28/1, 2011 at 15:57 Comment(6)
Sadly this has the same drawback as the other solution, a UI manager using a paint-over technique to dim the component would still give unsatisfactory results. Plus, the paint method will be called more times than the setForeground, so it's sightly more efficient to leave it unchanged and overwrite the other.Maffei
Doesn't it look exactly like the "desired"?Nguyetni
Where did I say that it wouldn't look correct? The problem is that it has the same flaw as my workaround: it is implementation dependent. A change in how the L&F or UI Manager achieves the disabled effect (I already described another way, there are more) and then it's broken.Maffei
It is fairly common that components look weird when you change their defaults looks and modify L&F. On the other hand who cares about MotifLookAndFeel in 2011...Nguyetni
It's a shame that unreliable hacks are accepted as commonplace... The least we can do is to identify them and mark them. Of course I wasn't thinking about Motif when I expressed my concern about the robustness of those methods, in my mind there was something more like a UI manager that used graphic layers and compositing.Maffei
Solution given by Antal S-Z does what I need . Is there anything wrong in that solution?Monogamist
D
7

Here's another hack, due to Michael Grimes, which shouldn't be affected by the particular look and feel. The trick is to make the combo box editable; the JTextField which is exposed as the editor supports the setDisabledTextColor method. And since you're disabling the combo box, it doesn't matter that it's editable! The code that I'm using to do this (translated from Scala) is the following:

JComboBox cb = ...;
...
cb.setEditable(true);
ComboBoxEditor editor = cb.getEditor()
JTextField     etf    = (JTextField)etf.getEditorComponent()
etf.setDisabledTextColor(UIManager.getColor("ComboBox.foreground"));
etf.setBackground(UIManager.getColor("ComboBox.background"));
// editor.setItem(format(obj));
cb.setEnabled(false);

The cast is guaranteed to succeed here because we're using a BasicComboBoxEditor, whose docs say "The editor is implemented as a JTextField." The commented-out line occurs because I'm using a custom renderer which prints integers with extra text surrounding them; calling setItem allows me to specify a similar string, and is necessary because the editor ignores the custom renderer. If you're using the default renderer, then you don't need to worry about that line; on the other hand, if you're using a more complicated renderer, then you might need to do something else entirely.

Despite the fact that this is a horrific kludge, it works, and it doesn't seem to rely on any implementation-defined features. The two places I could imagine this breaking are (a), if an editable combo box looks very different from an uneditable one (for instance, my first attempt didn't change the background color of the text field, which made it look wrong), or (b) if BasicComboBoxEditor stopped returning a JTextField (which seems less likely). But so far, it's serving my purposes.

Diversiform answered 22/7, 2011 at 23:1 Comment(0)
Y
6

Try this **

UIManager.put( "ComboBox.disabledBackground", new Color(212,212,210) );
UIManager.put( "ComboBox.disabledForeground", Color.BLACK );

**

Yuji answered 8/8, 2012 at 10:39 Comment(2)
That changes all combo boxes, I just want to change one.Maffei
+1, exactly what I need, spot on! (I want to behave all comboboxes identically)Gallard
R
0

The result can be achieved with the following code:

    Component editorComponent = comboBox.getEditor().getEditorComponent();
    if(editorComponent instanceof JTextComponent){
        ((JTextComponent)editorComponent).setDisabledTextColor(Color.black);
    }

I did not test it with several L&F, but it might make a difference, as this fires a PropertyChange event ("disabledTextColor"). Please see the docs.

Rufusrug answered 25/4, 2014 at 10:37 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.