Java Tips Weblog

  • Blog Stats

    • 2,572,079 hits
  • Categories

  • Archives

Combo Box With Hidden Data

Posted by Rob Camick on February 18, 2013

Typically a JComboBox is used to display a list of strings. There may be times when you need the items in the combo box to contain extra data so that you can do additional processing once an item is selected. What is the best way to do this?

The easiest way to accomplish this is to create a custom class that contains multiple properties. One property must be the property that will be displayed in the combo box. Other properties are added as required for additional processing. The key is to then make sure you override the toString() method of this custom class to return the display value. Why is overriding the toString() method so important?

  1. JComboBox uses a renderer to display text in the combo box. The default renderer gets the text to display by invoking the toString() method on each object added to the ComboBoxModel.
  2. JComboBox uses a KeySelectionManager to select items as the user types. In order to find matching items the default KeySelectionManager invokes the toString() method of each item as it searches through the ComboBoxModel.

In an application you may require several combo boxes with this type of functionality. Instead of creating a custom class for each combo box it is easier to create a general purpose class that can be used in many situations. The Item class may be class that you will consider using. It is a simple class that contains two properties:

  • value – this property contains the data hidden from the user but available to be used by the application. It can be a simple object like a String or it can be a custom object containing any number of additional properties.
  • description – this is a String that can be used by the renderer

Another feature of the Item class is that it implements the Comparable interface so that the SortedComboBoxModel (featured in another blog entry) can be used as the model for the JComboBox when required.

A simple example of a value/description Item might be a combo box that will contain a country code and country description. The country code would be hidden from the user and the country description will be used for display to the user. The code to create the combo box would be something like:

JComboBox<Item<String>> comboBox = new JComboBox<Item<String>>();
comboBox.addItem( new Item<String>("CA", "Canada" ) );
comboBox.addItem( new Item<String>("GB", "United Kingdom" ) );
comboBox.addItem( new Item<String>("US", "United States" ) );

In your ActionListener or ItemListener you would then access the country code value by doing:

JComboBox comboBox = (JComboBox)e.getSource();
Item item = (Item)comboBox.getSelectedItem();
String code = (String)item.getValue();

Using the Item class as a Wrapper

There may be times when you already have a custom object that you want to display in a combo box but the problem is that the toString() method has already been implemented and the implementation is not appropriate for display in a combo box. In this case you can use the Item class as a wrapper for your custom class.

For this next example we will assume we have a Car class with the properties “make” and “model” and we want the “model” to be displayed in the combo box. The code to create the combo box would be something like:

JComboBox<Item<Car>> comboBox = new JComboBox<Item<Car>>();
Car c1 = new Car("Ford", "Crown Victoria");
Car c2 = new Car("Ford", "Focus");
comboBox.addItem( new Item<Car>(c1, c1.getModel()) );
comboBox.addItem( new Item<Car>(c2, c2.getModel()) );

In your ActionListener or ItemListener you would then access the Car object by doing:

JComboBox comboBox = (JComboBox)e.getSource();
Item item = (Item)comboBox.getSelectedItem();
Car car = (Car)item.getValue();

Hopefully you will find the Item class helpful for including hidden data in a combo box. I couldn’t think of how to use a WebStart demo to show the usage of the Item class, so instead I have included my ItemTest code below which contains examples of the two approaches suggested here.

ComboBoxWithData

Note: Although the Item class was created for use with a JComboBox, there is no reason it can’t be used with other components that use renderers where the renderer relies on the toString() method for getting the text to render. For example, the Item class could also be used in a JList or JTable. Although, if used in a JTable it can only be used in a non-editable column.

Using a Custom Renderer

On various forums I have seen suggestions to use a custom render to solve this problem. That is, instead of overriding the toString() method of a custom class, the suggestion is to create a custom renderer to display a specific property from the class. I am not a big fan of this suggestion for the simple reason that the default KeySelectionManager will still use the toString() method of the class for selection purposes which can be very confusing to users. So if you decide to use this approach then you also need to implement a custom KeySelectionManager. This means you now have related logic in two separate classes.

Update:

If you decide to use the renderer approach then check out the Combo Box With Custom Renderer link below for a class that does most of the work for you.

Get The Code

Item.java
ItemDemo.java

See Also

Sorted Combo Box Model
Combo Box With Custom Renderer

Related Reading

Java API: Comparable
Java API: JComboBox.KeySelectionManager

13 Responses to “Combo Box With Hidden Data”

  1. goron59 said

    Or use a ListCellRenderer – it’s kind of what they’re for and you don’t have to abuse toString

    • Rob Camick said

      You missed my point about losing the functionality of the KeySelectionManager when you use a custom renderer. I would suggest that a custom renderer should only be used to add highlighting to the display. For example maybe you want to bold or color the selected item.

      Or maybe I’m missing somethin,g in which case I would appreciate you sending me a SSCCE where a custom renderer is used and the KeySelectionManager still works correctly.

      • Ricardo said

        Based on the swingx ObjectToStringConverter, that is basically a class that you can override to emulate toString() (different implementations for the same object type are possible), you can create a KeysSelectionManager and ListCellRenderer.
        In fact, I have KeySelectionManager and ListCellRenderer generic, that only depends on this ObjectToStringConverter, so the only logic is in the ObjectToStringConverter

      • Rob Camick said

        This suggestion has nothing to do with SwingX. It is a solution for people that don’t want to download the SwingX project.

  2. Kleopatra said

    100% ack with Goron: overriding toString is a bad idea – always. ListCellRenderer is the class responsible for configuring the display, both its content and its visual properties. If you are keen on the behaviour of the keySelectionManager the way to go is … implement your own ;-)

    Jeanette

    • Rob Camick said

      Overriding toString() should be done for every class. The API for the toString() method of the Object class suggests that: The result should be a concise but informative representation that is easy for a person to read. Using the description property would seem to be a reasonable implementation, maybe not perfect, but reasonable.

      Although I do see that when you use the Item class as a wrapper, the toString() implementation is not as reasonable since it will only represent one property of the wrapped class and not the class itself.

      Using the renderer approach you would need to create a custom class, a custom renderer and a custom key selection manager for every JComboBox with this type of functionality. This can result in class bloat very easily. Although to be fair I guess you could come up with a generic renderer and key selection manager. Reflection could be used to access a specific property from the class. Maybe I should persue this though for my next blog entry?

      This has been my first blog entry in over a year. Maybe I’ve run out of creative ideas? Maybe I should have stayed retired? ;-)

      • Anonymous said

        … maybe you should just have read SwingX code :-)

        1. _easy to read for a person_ – yeah sure, but the important part is the role of the person: the target here is the maintainer of the codebase, not the end-user

        2. _custom class_ – nothing special, in all real-world examples there already are full-fledged custom classes or at least pojos, which properties relevant to their visual representation

        3. _custom renderer_ – maybe, but that’s the small coin designed for the exact purpose of customizing the object’s visual representation. There are frameworks (like f.i. SwingX – can’t resist hammering that in :-) which provide even finer-grained building blocks, like (formatted) String/Icon/Value (to easily configure the content part) and Highlighter/HighlightPredicate to conditionally decorate a cell. Plus, that support is exactly the same across all “collection components” (table, tree, list, combo …) allowing free re-use of the custom very small block.

        4. _custom keySelectionListener_ – not with a framework (you see it coming :-) like Swingx which builds on bullet 2 above. Even without, it’s not rocket science to replace the extremely bad implementation of core (which relies on toString, tst) by one that relies on the string rep that the actual rendering component is using

        Welcome back :-)

      • Anonymous said

        darn … lost my long replay … :-(

        Short version: maybe you should have read SwingX code for a flexible consistent small-building-block solution :-)

      • Rob Camick said

        This wasn’t meant to be a complete framework type of solution (none of my suggestions are). Many beginning developers understand the basics of how a combo box works on an HTML page and want the same type of simple functionality. That is all this was addressing.

        Also, I was attempting to point out that many answers in the forums to use a custom renderer are incomplete because they always forget about the key selection manager.

        Anyway readers now have two points of view and can make their own decision. That is really all my suggestions are about is to get people thinking.

  3. Anonymous said

    Came in handy today… thanks sir… ;)

  4. Anonymous said

    Just what I’ve been looking for. Thanks man!.

  5. Sr. Ra said

    and for remove all items on this new JComboBox? default method throws java.lang.NullPointerException

Leave a comment