Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modify ComboBox display in Swing

I want to modify the display of a (non-editable) JComboBox in such a fashion that the currently selected entry has some extra text in the edit field (not the dropdown list, though).

Something like this:

Mockup

My first guess was to override the ComboBox’ model so that getSelectedItem returns a wrapper object modifying the display:

petList.setModel(new ComboBoxModel() {
    private Object selected;

    public void setSelectedItem(Object anItem) {
        selected = anItem;
    }

    public Object getSelectedItem() {
        return new ActiveComboItem(selected);
    }

    // … The rest of the methods are straightforward.
});

Where ActiveComboItem looks as follows:

static class ActiveComboItem {
    private final Object item;

    public ActiveComboItem(Object item) { this.item = item; }

    @Override
    public boolean equals(Object other) {
        return item == null ? other == null : item.equals(other);
    }

    @Override
    public String toString() { return String.format("Animal: %s", item); }
}

Indeed, this works as far as modifying the display goes. Unfortunately, the current entry is no longer marked as active:

Wrong display

(Note the missing check mark … or however the selection is displayed by your OS.)

Further inspection shows that the model’s getElementAt method is called with an index of -1 every time the user selects a new item in the box. This is only the case when using the modified selected item. When the model’s getSelectedItem method returns the plain object without wrapper, then the selected item is marked as selected in the dropdown box, and getElementAt is not called with an argument of -1.

Apparently, the ComboBox is comparing each item in turn to the currently active item but, despite my overriding the equals method, it finds no match. How can I fix this?

(Full, compilable code for this problem at gist.github.com)

like image 434
Konrad Rudolph Avatar asked Oct 24 '25 14:10

Konrad Rudolph


1 Answers

You need to provide a custom ListCellRenderer. The following works:

    final JComboBox animalCombo = new JComboBox(animals);
    animalCombo.setRenderer(new DefaultListCellRenderer() {
        @Override
        public Component getListCellRendererComponent(final JList list, Object value, final int index, final boolean isSelected,
                final boolean cellHasFocus) {

            if (index == -1) {
                value = "Animal: " + value;
            }

            return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
        }
    });

index is -1 when the value its painting is the one that's not in the dropdown.

For future reference, when you just want to change how something is displayed in Swing, you never want to modify the backing model. Every component has a renderer, and generally you just need to slightly modify the default one.

like image 93
Reverend Gonzo Avatar answered Oct 28 '25 06:10

Reverend Gonzo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!