Question

I have a list of Customer objects that I need to have selectable from a JComboBox. From what I read I need to implement a custom renderer to have the fields I want displayed in the list.

I want my JComboBox to have entries formatted as such:

+----------------------------------------------+
|  Customer Name - Contact - City, State    V  |
+==============================================+
|  Customer #2 Name - Contact - City, State    |
|  Customer #3 Name - Contact - City, State    |
|  Customer #4 Name - Contact - City, State    |
|  Customer #5 Name - Contact - City, State    |
+----------------------------------------------+

I used this code:

public class CustomerListCellRenderer extends DefaultListCellRenderer {

@Override
public Component getListCellRendererComponent(
        JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
    super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
    if (value instanceof Customer) {
        Customer c = (Customer) value;

        StringBuffer sb = new StringBuffer();
        if (c.getCompany() != null && c.getCompany().length() > 0) {
            sb.append(c.getCompany());
        }
        sb.append(" - ");
        if (c.getCompany() != null && c.getCompany().length() > 0) {
            sb.append(c.getContact());
        }
        sb.append(" - ");
        if (c.getCompany() != null && c.getCompany().length() > 0) {
            sb.append(c.getCity());
            sb.append(", ");
        }            
        if (c.getCompany() != null && c.getCompany().length() > 0) {
            sb.append(c.getState());
        }

        setText(sb.toString());
    }
    return this;
  }
}

This doesn't work correctly under Solaris / Unix / Linux using the system GTKLookAndFeel. The background of the input area of the combobox is not drawn and no border is drawn around it. (See screenshot below). Is there another way to achieve this that will work correctly across the 3 major platforms (Win/Mac/GTK)? Can I do a converter to do this and only manipulate the data not the GUI?

My current workaround is to override toString() on my Customer object to display each record in the format I want, but looking for other ideas.

alt text

Nick

Was it helpful?

Solution

Same issue, I did this in order to customize it for showing icons:

private static class CustomComboBoxRenderer extends DefaultListCellRenderer
{
    private final ListCellRenderer backend;

    public CustomComboBoxRenderer(ListCellRenderer backend)
    {
        this.backend = backend;
    }

    @Override
    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)
    {
        Component component = backend.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
        if(component instanceof JLabel == false)
            component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
        JLabel label = (JLabel)component;
        label.setIcon(Icons.COMPONENT);
        return label;
    }
}

Then assigned the renderer like this:

comboBox.setRenderer(new CustomComboBoxRenderer(comboBox.getRenderer()));

This has worked out fine for me, so far.

OTHER TIPS

Try this:

public Component getListCellRendererComponent(
        JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
    if (value instanceof Customer) {
        Customer c = (Customer) value;

        StringBuffer sb = new StringBuffer();
        if (c.getCompany() != null && c.getCompany().length() > 0) {
            sb.append(c.getCompany());
        }
        sb.append(" - ");
        if (c.getCompany() != null && c.getCompany().length() > 0) {
            sb.append(c.getContact());
        }
        sb.append(" - ");
        if (c.getCompany() != null && c.getCompany().length() > 0) {
            sb.append(c.getCity());
            sb.append(", ");
        }            
        if (c.getCompany() != null && c.getCompany().length() > 0) {
            sb.append(c.getState());
        }

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

Also use a StringBuilder not a StringBuffer (this is a single threaded situation).

Also also it looks like you have cut and paste errors in the code for instance:

        if (c.getCompany() != null && c.getCompany().length() > 0) {
            sb.append(c.getState());
        }

Is checking the Company member and using the State member.

The DefaultListCellRenderer extends JLabel and looks like JLabel. If you have non-editable ComboBox then Renderer returned via getRenderer is used for painting drop down list area and also for "input" area. Try to play with border/foreground/background settings for ComboBox and renderer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top