Create a Collections-Aware JComboBox #20
Chapter 2, Lists and Combos
|
95
HACK
Using toString( ) on the strings will be the same as the default renderer,
simply drawing Proton, Neutron, and Electron in the list (see Figure 2-12).
The resulting change would look like Figure 2-13.
Using reflection for cell renderers is a very powerful concept because you
can reuse potentially complicated code with very little additional effort.
Using it to display strings is just a trivial example. Imagine you had a bunch
of objects representing entries from an RSS feed. Instead of creating a cus-
tom renderer or wrapping the entries in objects with a custom
toString( )
method, you could use the GenericListCellRenderer with getTitle( ) to
automatically call the
getTitle( ) method on the entry objects—no new
subclasses or extra code. Just a single string and the renderer takes care of
the rest. That is the power of reflection.
H A C K
#20
Create a Collections-Aware JComboBox Hack #20
You’ve moved on from Vector; your combo boxes should, too.
JComboBox is one of Swing’s oldest components. Unfortunately, it accepts
arrays of objects and
Vectors only. Now that Collections objects like List
have been part of the JDK for years, it would be nice to use them directly in
a combo box without shuffling objects in and out of arrays. Fortunately, the
JComboBox uses an MVC (Model-View-Controller) architecture, so you can
solve this problem with a simple implementation of a
ComboBoxModel.
Figure 2-12. Renderer using the toString( ) method
Figure 2-13. Renderer using the hashCode( ) method
96
|
Chapter 2, Lists and Combos
#20 Create a Collections-Aware JComboBox
HACK
To start, you need to figure out what the custom model should do. For our
purposes, it needs to accept a
List in the constructor and preserve any
ordering supplied. Another nifty feature would be automatic updates. If you
add or delete values to the
List
, the combo box should update itself auto-
matically. Example 2-22 is a good start.
This implementation is pretty much what you’d expect. Each method in
ComboBoxModel is implemented (along with its parent interface,
ListDataModel). The constructor saves a reference to the List and selects the
first element if there is one. The
selectedItem accessor works as expected,
using the selected variable.
getElementAt( ) and getSize( ) both pass the
work on to the underlying
List, and the ListDataListener methods work
Example 2-22. A basic combo box to accept lists
public class ListComboBoxModel implements ComboBoxModel {
protected List data;
public ListComboBoxModel(List list) {
this.listeners = new ArrayList( );
this.data = list;
if(list.size( ) > 0) {
selected = list.get(0);
}
}
protected Object selected;
public void setSelectedItem(Object item) {
this.selected = item;
}
public Object getSelectedItem( ) {
return this.selected;
}
public Object getElementAt(int index) {
return data.get(index);
}
public int getSize( ) {
return data.size( );
}
protected List listeners;
public void addListDataListener(ListDataListener l) {
listeners.add(l);
}
public void removeListDataListener(ListDataListener l) {
this.listeners.remove(l);
}
}
Create a Collections-Aware JComboBox #20
Chapter 2, Lists and Combos
|
97
HACK
with a second List for managing the listeners. The important thing to notice
here is that the code saves the reference to the
List that was passed in,
rather than creating a copy. This means that the model will always be in
sync with the underlying list implementation. If you call
list.add("new
item")
, it will show up in the combo box automatically.
To test this, use the simple class in Example 2-23.
The program creates a
JComboBox that uses the new ListComboBoxModel. First,
it creates a list, populates it with data, passes it to the
ListComboBoxModel
constructor, and then sends that to the new JComboBox( ). There is also a
button that adds a new item to the list when clicked.
When you compile and run this program, it...doesn’t work! The addition to
the
List doesn’t show up in the combo box. A look over the API might
remind you of the
ListDataListener class. When setModel( ) is called, the
Example 2-23. Testing the List-based JComboBox
public class CBTest {
public static void main(String[] args) {
JFrame frame = new JFrame("Hack #4: Create a Collections-Aware
JComboBox");
Container root = frame.getContentPane( );
root.setLayout(new BoxLayout(root,BoxLayout.X_AXIS));
// List combo box
final List list = new ArrayList( );
list.add("Blinky");
list.add("Pinky");
list.add("Inky");
final ListComboBoxModel mod2 = new ListComboBoxModel(list);
JComboBox cb2 = new JComboBox( );
cb2.setModel(mod2);
root.add(cb2);
final JButton bt2 = new JButton("Add Item");
bt2.addActionListener(new ActionListener( ) {
public void actionPerformed(ActionEvent evt) {
list.add("Clyde");
}
});
root.add(bt2);
// show the frame
frame.pack( );
frame.setVisible(true);
}
}

Get Swing Hacks now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.