Subpages: 1. Combo Boxes: JComboBox
2. Basic JComboBox example
3. Custom model and renderer
4. Comboboxes with memory
5. Custom editing
9.2 Basic JComboBox example
This example displays information about popular cars in two symmetrical panels to provide a natural means of comparison. To be more or less realistic, we need to take into account that any car model comes in several trim lines which actually determine the car's characteristics and price. Numerous characteristics of cars are available on the web. For this simple example we've selected the following two-level data structure:
CAR
Name Type Description
Name String Model's name
Manufacturer String Company manufacturer
Image Icon Model's photograph
Trims Vector A collection of model's trims
TRIM
Name Type Description
Name String Trim's name
MSRP int Manufacturer's suggested retail price
Invoice int Invoice price
Engine String Engine description

Figure 9.1 Dynamically changeable JComboBoxes allowing comparison of car model and trim information.
<<file figure9-1.gif>>
The Code: ComboBox1.java
see \Chapter9\1
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
public class ComboBox1 extends JFrame
{
public ComboBox1() {
super("ComboBoxes [Compare Cars]");
getContentPane().setLayout(new BorderLayout());
Vector cars = new Vector();
Car maxima = new Car("Maxima", "Nissan", new ImageIcon(
"maxima.gif"));
maxima.addTrim("GXE", 21499, 19658, "3.0L V6 190-hp");
maxima.addTrim("SE", 23499, 21118, "3.0L V6 190-hp");
maxima.addTrim("GLE", 26899, 24174, "3.0L V6 190-hp");
cars.addElement(maxima);
Car accord = new Car("Accord", "Honda", new ImageIcon(
"accord.gif"));
accord.addTrim("LX Sedan", 21700, 19303, "3.0L V6 200-hp");
accord.addTrim("EX Sedan", 24300, 21614, "3.0L V6 200-hp");
cars.addElement(accord);
Car camry = new Car("Camry", "Toyota", new ImageIcon(
"camry.gif"));
camry.addTrim("LE V6", 21888, 19163, "3.0L V6 194-hp");
camry.addTrim("XLE V6", 24998, 21884, "3.0L V6 194-hp");
cars.addElement(camry);
Car lumina = new Car("Lumina", "Chevrolet", new ImageIcon(
"lumina.gif"));
lumina.addTrim("LS", 19920, 18227, "3.1L V6 160-hp");
lumina.addTrim("LTZ", 20360, 18629, "3.8L V6 200-hp");
cars.addElement(lumina);
Car taurus = new Car("Taurus", "Ford", new ImageIcon(
"taurus.gif"));
taurus.addTrim("LS", 17445, 16110, "3.0L V6 145-hp");
taurus.addTrim("SE", 18445, 16826, "3.0L V6 145-hp");
taurus.addTrim("SHO", 29000, 26220, "3.4L V8 235-hp");
cars.addElement(taurus);
Car passat = new Car("Passat", "Volkswagen", new ImageIcon(
"passat.gif"));
passat.addTrim("GLS V6", 23190, 20855, "2.8L V6 190-hp");
passat.addTrim("GLX", 26250, 23589, "2.8L V6 190-hp");
cars.addElement(passat);
getContentPane().setLayout(new GridLayout(1, 2, 5, 3));
CarPanel pl = new CarPanel("Base Model", cars);
getContentPane().add(pl);
CarPanel pr = new CarPanel("Compare to", cars);
getContentPane().add(pr);
WindowListener wndCloser = new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
};
addWindowListener(wndCloser);
pl.selectCar(maxima);
pr.selectCar(accord);
setResizable(false);
pack();
setVisible(true);
}
public static void main(String argv[]) {
new ComboBox1();
}
}
class Car
{
protected String m_name;
protected String m_manufacturer;
protected Icon m_img;
protected Vector m_trims;
public Car(String name, String manufacturer, Icon img) {
m_name = name;
m_manufacturer = manufacturer;
m_img = img;
m_trims = new Vector();
}
public void addTrim(String name, int MSRP, int invoice,
String engine) {
Trim trim = new Trim(this, name, MSRP, invoice, engine);
m_trims.addElement(trim);
}
public String getName() { return m_name; }
public String getManufacturer() { return m_manufacturer; }
public Icon getIcon() { return m_img; }
public Vector getTrims() { return m_trims; }
public String toString() { return m_manufacturer+" "+m_name; }
}
class Trim
{
protected Car m_parent;
protected String m_name;
protected int m_MSRP;
protected int m_invoice;
protected String m_engine;
public Trim(Car parent, String name, int MSRP, int invoice,
String engine) {
m_parent = parent;
m_name = name;
m_MSRP = MSRP;
m_invoice = invoice;
m_engine = engine;
}
public Car getCar() { return m_parent; }
public String getName() { return m_name; }
public int getMSRP() { return m_MSRP; }
public int getInvoice() { return m_invoice; }
public String getEngine() { return m_engine; }
public String toString() { return m_name; }
}
class CarPanel extends JPanel
{
protected JComboBox m_cbCars;
protected JComboBox m_cbTrims;
protected JLabel m_lblImg;
protected JLabel m_lblMSRP;
protected JLabel m_lblInvoice;
protected JLabel m_lblEngine;
public CarPanel(String title, Vector cars) {
super();
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
setBorder(new TitledBorder(new EtchedBorder(), title));
JPanel p = new JPanel();
p.add(new JLabel("Model:"));
m_cbCars = new JComboBox(cars);
ActionListener lst = new ActionListener() {
public void actionPerformed(ActionEvent e) {
Car car = (Car)m_cbCars.getSelectedItem();
if (car != null)
showCar(car);
}
};
m_cbCars.addActionListener(lst);
p.add(m_cbCars);
add(p);
p = new JPanel();
p.add(new JLabel("Trim:"));
m_cbTrims = new JComboBox();
lst = new ActionListener() {
public void actionPerformed(ActionEvent e) {
Trim trim = (Trim)m_cbTrims.getSelectedItem();
if (trim != null)
showTrim(trim);
}
};
m_cbTrims.addActionListener(lst);
p.add(m_cbTrims);
add(p);
p = new JPanel();
m_lblImg = new JLabel();
m_lblImg.setHorizontalAlignment(JLabel.CENTER);
m_lblImg.setPreferredSize(new Dimension(140, 80));
m_lblImg.setBorder(new BevelBorder(BevelBorder.LOWERED));
p.add(m_lblImg);
add(p);
p = new JPanel();
p.setLayout(new GridLayout(3, 2, 10, 5));
p.add(new JLabel("MSRP:"));
m_lblMSRP = new JLabel();
p.add(m_lblMSRP);
p.add(new JLabel("Invoice:"));
m_lblInvoice = new JLabel();
p.add(m_lblInvoice);
p.add(new JLabel("Engine:"));
m_lblEngine = new JLabel();
p.add(m_lblEngine);
add(p);
}
public void selectCar(Car car) { m_cbCars.setSelectedItem(car); }
public void showCar(Car car) {
m_lblImg.setIcon(car.getIcon());
if (m_cbTrims.getItemCount() > 0)
m_cbTrims.removeAllItems();
Vector v = car.getTrims();
for (int k=0; k<v.size(); k++)
m_cbTrims.addItem(v.elementAt(k));
m_cbTrims.grabFocus();
}
public void showTrim(Trim trim) {
m_lblMSRP.setText("$"+trim.getMSRP());
m_lblInvoice.setText("$"+trim.getInvoice());
m_lblEngine.setText(trim.getEngine());
}
}
Understanding the Code
Class ComboBox1
Class ComboBox1 extends JFrame to implement the frame container for this example. It has no instance variables. The constructor of the ComboBox1 class creates a data collection with car information as listed above. A collection of cars is stored in Vector cars, and each car, in turn, receives one or more Trim instances. Other than this, the ComboBox1 constructor doesn't do much. It creates two instances of CarPanel (see below) and arranges them in a GridLayout. These panels are used to select and display car information. Finally two cars are initially selected in both panels.
Class Car
Car is a typical data object encapsulating three data fields listed at the beginning of this section: car name, manufacturer, and image. In addition, it holds the m_trims vector representing a collection of Trim instances.
Method addTrim() creates a new Trim instance and adds it to the m_trims vector. The rest of this class implements typical getXX() methods to allow access to the protected data fields.
Class Trim
Trim encapsulates four data fields listed at the beginning of this section: trim name, suggested retail price, invoice price, and engine type. In addition, it holds a reference to the parent Car instance. The rest of this class implements typical getXX() methods to allow access to the protected data fields.
Class CarPanel
This class extends JPanel to provide the GUI framework for displaying car information. Six components are declared as instance variables:
JComboBox m_cbCars: Combo box to select a car model.
JComboBox m_cbTrims: Combo box to select a car trim for the selected model.
JLabel m_lblImg: Label to display the model's image.
JLabel m_lblMSRP: Label to display the MSRP.
JLabel m_lblInvoice: Label to display the invoice price.
JLabel m_lblEngine: Label to display the engine description.
Two combo boxes are used to select cars and trims respectively. Note that Car and Trim data objects are used to populate these combo boxes, so the actual displayed text is determined by their toString() methods. Both combo boxes receive ActionListeners to handle item selection. Then a Car item is selected, which triggers a call to the showCar() method described below. Similarly, a selection of a Trim item triggers a call to the showTrim() method.
The rest of the CarPanel constructor builds JLabels to display a car's image and trim data. Note how layouts are used in this example. A y-oriented BoxLayout creates a vertical axis used to allign and position all components. The combo boxes and supplementary labels are encapsulated in horizontal JPanels. JLabel m_lblImg receives a custom preferred size to reserve enough space for the photo image. This label is encapsulated in a panel (with its default FlowLayout) to ensure that this component will be centered over the container's space. The rest of CarPanel is occupied by the six labels, which are hosted by a 3x2 GridLayout.
Method selectCar() allows us to select a car programmatically from outside this class. It invokes the setSelectedItem() method on the m_cbCars combo box. Note that this call will trigger an ActionEvent which will be captured by the proper listener, resulting in a showCar() call.
Method showCar() updates the car image and updates the m_cbTrims combo box to display the corresponding trims of the selected model. The (getItemCount() > 0) condition is necessary because Swing throws an exception if removeAllItems() is invoked on an empty JComboBox. Finally, focus is transferred to the m_cbTrims component.
Method showTrim() updates the contents of the labels displaying trim information: MSRP, invoice price, and engine type.
Running the Code
Figure 9.1 shows the ComboBox1 application displaying two cars simultaneously for comparison. Note that all initial information is displayed correctly. Try experimenting with various selections and note how the combo box contents change dynamically.
UI Guideline : Symmetrical Layout
In this example, the design avoids the problem of having to align the different length comboboxes by using a symmetrical layout. Overall the window has a good balance and good use of white space, as in turn do each of the bordered panes used for individual car selections.



RSS feed Java FAQ News