2

Is there a comparable mechanism to the .NET "set DisplayMember" for the JListBox Swing component?

Overriding the toString() method is not sufficient because I also want to be able to change the display member at runtime.

I also looked into implementing my own ListCellRenderer, but found it not very convenient.

Ist there a easier or more elegant approach?

Thanks for your time.

Julian Lettner
  • 3,309
  • 7
  • 32
  • 49
  • 1
    Overriding the toString() or providing a custom renderer are the two common approaches for customizing the display. I fail to see what your concerns are with either approach. Post your http://sscce.org that shows the problems you are having with either approach. – camickr Feb 12 '10 at 16:22
  • Thanks, you already helped me with saying that there are no other common approaches. I came up with a satisfying solution based on implementing a custom ListCellRenderer. – Julian Lettner Feb 12 '10 at 17:42

2 Answers2

0

You should create a wrapper class around your business object that overrides toString(). This way you keep your own object clean and can at runtime swap wrappers.

public class MyWrapper()
{
    private MyBusinessObject object;

    public String toString()
    {
        return object.getImportantString();
    }
}
willcodejavaforfood
  • 43,223
  • 17
  • 81
  • 111
  • Hey, I thought of something like that too. The problem with this is, that your ListModel has to contain the wrapped objects instead of pure domain objects. So when you want to change the displayed member at runtime you have to create a whole bunch of new wrappers. Plus you have to define that wrapper classes, which leaves you with many not particularly useful classes. – Julian Lettner Feb 12 '10 at 17:33
0

I came up with a satisfying solution based on implementing a custom ListCellRenderer.

import java.awt.Component;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JList;
import javax.swing.ListCellRenderer;

public class DynamicCellRenderer implements ListCellRenderer {
    private final ListCellRenderer listCellRenderer;
    private String displayMember;

    public DynamicCellRenderer(String displayMember) {
        this(displayMember, new DefaultListCellRenderer());
    }

    public DynamicCellRenderer(String displayMember, ListCellRenderer wrapped) {
        listCellRenderer = wrapped;
        this.displayMember = displayMember;
    }

    @Override
    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
        Object displayMemberValue = getDisplayMemberValue(value);
        return listCellRenderer.getListCellRendererComponent(list, displayMemberValue, index, isSelected, cellHasFocus);
    }

    private Object getDisplayMemberValue(Object value) {
        // value is the domain class
        // only works if display member is a method, TODO: fallback to field
        // displayMember is something like "getName" -> value.getName() gets called
        try {
            return value.getClass().getMethod(displayMember).invoke(value);
        } catch (Exception ex) {
            // if anything went wrong it is the programmers fault -> propagate exception
            throw new RuntimeException(ex);
        }
    }

    public String getDisplayMember() {
        return displayMember;
    }

    public void setDisplayMember(String displayMember) {
        this.displayMember = displayMember;
    }

}

In your client GUI code you can do something like this:

jListBox1.setCellRenderer(new DynamicCellRenderer("getName"));
...
...
// and later at some point
((DynamicCellRenderer) jListBox1.getCellRenderer()).setDisplayMember("getEmail");
Julian Lettner
  • 3,309
  • 7
  • 32
  • 49
  • 2
    I'd also suggest storing the method when it changes rather than calling value.getClass().getMethod(displayMember) on every re-rendering. No need to search for the method if it hasn't changed. – Jeff Storey Feb 15 '10 at 01:40