Subpages: 1. Combo Boxes: JComboBox
2. Basic JComboBox example
3. Custom model and renderer
4. Comboboxes with memory
5. Custom editing
Chapter 9. Combo Boxes
In this chapter:
- JComboBox
- Basic JComboBox example
- Custom model and renderer
- Combo box with memory
- Custom editing
9.1 JCombobox
class javax.swing.JComboBox
This class represents a basic GUI component which consists of two parts:
A popup menu (an implementation of javax.swing.plaf.basic.ComboPopup). By default this is a JPopupMenu sub-class (javax.swing.plaf.basic.BasicComboPopup) containing a JList in a JScrollPane.
A button acting as a container for an editor or renderer component, and an arrow button used to display the popup menu.
The JList uses a ListSelectionModel (see chapter 10) allowing SINGLE_SELECTION only. Apart from this, JComboBox directly uses only one model, a ComboBoxModel, which manages data in its JList.
A number of constructors are available to build a JComboBox. The default constructor can be used to create a combo box with an empty list, or we can pass data to a constructor as a one-dimensional array, a Vector, or as an implementation of the ComboBoxModel interface (see below). The last variant allows maximum control over the properties and appearance of a JComboBox, as we will see.
As other complex Swing components, JComboBox allows a customizable renderer for displaying each item in its drop-down list (by default a JLabel sub-class implementation of ListCellRenderer), and a customizable editor to be used as the combo box's data entry component (by default an instance of ComboBoxEditor which uses a JTextField). We can use the existing default implementations of ListCellRenderer and ComboBoxEditor, or we can create our own according to our particular needs (which we will see later in ths chapter). Note that unless we use a custom renderer, the default renderer will display each element as a String defined by that object's toString() method (the only exceptions to this are Icon implementations which will be renderered as they would be in any JLabel). Also note that a renderer returns a Component, but that component is not interactive and is only used for display purposes (i.e. it acts as a "rubber stamp"API). For instance, if a JCheckBox is used as a renderer we will not be able to check and uncheck it. Editors, however, are fully interactive.
Similar to JList (next chapter), this class uses ListDataEvents to deliver information about changes in the state of its drop-down list's model. ItemEvents and ActionEvents are fired when the current selection changes (from any source--programmatic or direct user input). Correspondingly, we can attach ItemListeners and ActionListeners to receive these events.
The drop-down list of a JComboBox is a popup menu containing a JList (this is actually defined in the UI delegate, not the component itself) and can be programmatically displayed using the showPopup() and hidePopup() methods. As any other Swing popup menu (which we will discuss in chapter 12), it can be displayed as either heavyweight or lightweight. JComboBox provides the setLightWeightPopupEnabled() method allowing us to choose between these modes.
JComboBox also defines an inner interface called KeySelectionManager that declares one method, selectionForKey(char aKey, ComboBoxModel aModel), which should be overriden to return the index of the list element to select when the list is visible (popup is showing) and the given keyboard character is pressed.
The JComboBox UI delegate represents JComboBox graphically by a container with a button which encapsulates an arrow button and either a renderer displaying the currently selected item, or an editor allowing changes to be made to the currently selected item. The arrow button is displayed on the right of the renderer/editor and will show the popup menu containing the drop-down list when clicked.
Note: Because of the JComboBox UI delegate construction, setting the border of a JComboBox does not have the expected effect. Try this and you will see that the container containing the main JComboBox button gets the assigned border, when in fact we want that button to recieve the border. There is no easy way to set the border of this button without customizing the UI delegate, and we hope to see this limitation disappear in a future version.
When a JComboBox is editable (which it is not by default) the editor component will allow modification of the currenly selected item. The default editor will appear as a JTextField accepting input. This text field has an ActionListener attached that will accept an edit and change the selected item accoringly when/if the Enter key is pressed. If the focus changes while editing, all editing will be cancelled and a change will not be made to the selected item.
JComboBox can be made editable with its setEditable() method, and we can specify a custom ComboBoxEditor with JComboBox's setEditor() method.. Setting the editable property to true causes the UI delegate to replace the renderer component in the button to the specified editor component. Similarly, setting this property to false causes the editor in the button to be replaced by a renderer.
The cell renderer used for a JComboBox can be assigned/retrieved with the setRenderer()/getRenderer() methods. Calls to these methods actually get passed to the JList contained in the combo box's popup menu.
9.1.1 The ComboBoxModel interface
abstract interface javax.swing.ComboBoxModel
This interface extends the ListModel interface which handles the combo box drop-down list's data. This model separately handles its selected item with two methods, setSelectedItem() and getSelectedItem().
9.1.2 The MutableComboBoxModel interface
abstract interface javax.swing.MutableComboBoxModel
This interface extends ComboBoxModel and adds four methods to modify the model's contents dynamically: addElement(), insertElementAt(), removeElement(), removeElementAt().
9.1.3 DefaultComboBoxModel
class javax.swing.DefaultComboBoxModel
This class represents the default model used by JComboBox, and implements MutableComboBoxModel. To programmatically select an item we can call its setSelectedItem() method. Calling this method, as well as any of the MutableComboBoxModel methods mentioned above, will cause a ListDataEvent to be fired. To capture these events we can attatch ListDataListeners with DefaultComboBoxModel's addListDataListener() method. We can also remove these listeners with its removeListDataListener() method.
9.1.4 The ListCellRenderer interface
abstract interface javax.swing.ListCellRenderer
This is a simple interface used to define the component to be used as a renderer for the JComboBox drop-down list. It declares one method, getListCellRendererComponent(JList list, Object value, int Index, boolean isSelected, boolean cellHasFocus), which is called to return the component used to represent a given combo box element visually. The component returned by this method is not at all interactive and is used for display purposes only (referred to as a "rubber stamp" in the API docs).
When in noneditable mode, -1 will be passed to this method to return the component used to represent the selected item in the main JComboBox button. Normally this component is the same as the component used to display that same element in the drop-down list.
9.1.5. DefaultListCellRenderer
class javax.swing.DefaultListCellRenderer
This is the concrete implementation of the ListCellRenderer interface used by JList by default (and this by JComboBox's JList). This class extends JLabel and its getListCellRenderer() method returns a this reference, renders the given value by setting its text to the String returned by the value's toString() method (unless the value is an instance of Icon, in which case it will be rendered as it would be in any JLabel), and uses JList foreground and background colors depending on whether or not the given item is selected.
Note: Unfortunately there is no easy way to access JComboBox's drop-down JList, which prevents us from assigning new foreground and background colors. Ideally JComboBox would provide this communication with its JList, and we hope to see this functionality in a future version.
A single static EmptyBorder instance is used for all cells that do not have the current focus. This border has top, bottom, left, and right spacing of 1, and unfortunately cannot be re-assigned.
9.1.6 The ComboBoxEditor interface
abstract interface javax.swing.ComboBoxEditor
This interface describes the JComboBox editor. The default editor is provided by the only implementing class, javax.swing.plaf.basic.BasicComboBoxEditor. But we are certainly not limited to this component. It is the purpose of this interface to allow us to implement our own custom editor. The getEditorComponent() method should be overridden to return the editor component to use. BasicComboBoxEditor's getEditorComponent() method returns a JTextField that will be used for the currently selected combo box item. Unlike cell renderers, components returned by the getEditorComponent() method are fully interactive and do not act like rubber stamps.
The setItem() method is intended to tell the editor which element to edit (this is called when an item is selected from the drop-down list). The getItem() method is used to return the object being edited (a String using the default editor).
The selectAll() method is intended to select all items to be edited, and the default editor implements this by selecting all text in the text field (though this method is not used in the default implementation, we might consider calling it from our own the setItem() method to show all text selected when editing starts).
ComboBoxEditor also decalres functionality for attaching and removing ActionListeners which are notified when an edit is accepted. In the default editor this occurs when Enter is pressed while the text field has the focus.
Note: Unfortunately Swing does not provide an easily reusable ComboBoxEditor implementation, forcing custom implementations to manage all ActionListener and item selection/modification functionality from scratch (we hope to see this limitation accounted for in a future Swing release).
UI Guideline : Advice on Usage and Design Usage
Comboboxes and List Boxes are very similar. In fact a Combobox is an Entry Field with a drop down List Box. Deciding when to use one or another can be difficult. Our advice is to think about reader output rather than data input. When the reader only needs to see a single item then a Combobox is the choice. Use a Combobox where a single selection is made from a collection and for reading purposes it is only necessary to see a single item, e.g. Currency USD.
Design
There are a number of things which affect the usability of a combobox. Beyond more than a few items, they become unusable unless the data is sorted in some logical fashion e.g. alphabetical, numerical. When a list gets longer, usability is affected again.Once a list gets beyond a couple of hundred items, even when sorted, it becomes very slow for the user to locate specific item in the list. Some implementations have solved this by offering an ability to type in partial text and the list "jumps" to the best match or partial match item e.g. type in "ch" and the combobox will jump to "Chevrolet" as in the example in this chapter. You may like to consider such an enhancement to a JCombobox to improve the usability in longer lists.
There are a number of graphical considerations too. Like all other data entry fields, comboboxes should be aligned to fit attractively into a panel. However, this can be problematic. You must avoid making a combobox which is simply too big for the list items contained e.g. a combobox for currency code ( typicall USD for U.S. Dollars ) only needs to be 3 characters long. So don't make it big enough to take 50 characters. It will look unbalanced. Another problem, is the nature of the list items. If you have 50 items in a list where most items are around 20 characters but one item is 50 characters long then should you make the combobox big enough to display the longer one? Well maybe but for most occasions your display will be unbalanced again. It is probably best to optimise for the more common length, providing the the longer one still has meaning when read in its truncated form. One solution to displaying the whole length of a truncated item is to use the tooltip facility. When the User places the mouse over an item, a tooltip appears with the full length data.
One thing you must never do is dynamically resize the combobox to fit a varying length item selection. This will provide alignment problems and may also add a usability problem because the pull-down button may become a moving target which denies the user the option to learn its position with directional memory.


RSS feed Java FAQ News