Building a Drop-Down Menu Button #10
Chapter 1, Basic JComponents
|
43
HACK
H A C K
#10
Building a Drop-Down Menu Button
Hack #10
This hack shows how to build a color chooser as a proper drop-down
component. It will behave like
JComboBox but without the extension
headaches of Sun’s version of the class.
Most custom Swing components are created with simple subclasses of the
standard base classes in
javax.swing
. This works fine most of the time, but
every now and then you need to build something where there is no easy
standard component to start with. Even worse, sometimes the obvious
choice for your starting point is a component so convoluted that you can’t
figure out where to start. Still, you’d rather not reimplement the wheel. No,
I’m not talking about
JTree or JTable—I’m referring to the JComboBox. It
seems like such a simple component, but the implementation is fiendishly
complex.
Most large applications use components that feel like the
JComboBox, but do
something entirely different, like select a color or show a history list. A quick
search through the
JComboBox API doesn’t turn up any obvious extension
points. You could customize it with some cell renderers, but if you need a
component that doesn’t show a list of data, you are pretty much out of luck.
The source to
JComboBox is not very helpful either. The work is spread out
over several UI classes in the various Look and Feel (L&F) packages. If you
did customize one of those, your component would look out of place when
used in a different L&F. The only real option is to write your own combo
box, which is pretty easy except for the actual drop-down part. You need to
show a component on top of the others, poking out of the frame occasion-
ally, but without any decorations of its own. It should be just a borderless
floating box. Digging through Swing’s source code reveals the secret ingredi-
ent: a
JWindow.
JWindow is a subclass of Window but not of Frame. This means it has no decora-
tions on the side, and it is hidden from the Dock and Taskbar. This is
exactly what you want from a pop up. Care must be taken when creating it,
however, as you must ensure the window appears only on top of the exist-
ing components, and that it disappears when something else gains focus or
the window moves. Fortunately, you can do all of this with one composite
component and a few event listeners.
DropDownComponent will be a composite of the visible component, a down
arrow trigger button, and the hidden component that will appear in the pop
up. By thinking of your custom component as a composite of existing com-
ponents, you can make it very flexible. Additionally, subclasses must be able
to add different components to make something new out of the same pieces.
44
|
Chapter 1, Basic JComponents
#10 Building a Drop-Down Menu Button
HACK
Example 1-21 is the start of a DropDownComponent class. It extends JComponent
directly and implements both the action and ancestor listener interfaces. It
assembles the visible and drop-down components passed into its construc-
tor with an arrow trigger and the listeners.
The arrow is just a
JButton with a MetalComboBoxIcon. Reusing this arrow lets
the code pick up any Metal Look and Feel customizations. The last line of
the constructor calls another method in the class,
setupLayout( ), to posi-
tion the arrow next to the visible component while letting the component
still grow:
protected void setupLayout( ) {
GridBagLayout gbl = new GridBagLayout( );
GridBagConstraints c = new GridBagConstraints( );
setLayout(gbl);
c.weightx = 1.0; c.weighty = 1.0;
c.gridx = 0; c.gridy = 0;
c.fill = c.BOTH;
gbl.setConstraints(visible_comp,c);
add(visible_comp);
c.weightx = 0;
c.gridx++;
gbl.setConstraints(arrow,c);
add(arrow);
}
Example 1-21. Skeleton for a drop-down combo box
public class DropDownComponent extends JComponent
implements ActionListener, AncestorListener {
protected JComponent drop_down_comp;
protected JComponent visible_comp;
protected JButton arrow;
protected JWindow popup;
public DropDownComponent(JComponent vcomp, JComponent ddcomp) {
drop_down_comp = ddcomp;
visible_comp = vcomp;
arrow = new JButton(new MetalComboBoxIcon( ));
Insets insets = arrow.getMargin( );
arrow.setMargin( new Insets( insets.top, 1, insets.bottom, 1 ) );
arrow.addActionListener(this);
addAncestorListener(this);
setupLayout( );
}
}

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.