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:
- Basic JComboBox example
- Custom model and renderer
- Combo box with memory
- Custom editing
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.
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().
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.
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.
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.