第18章 组合框
由JComboBox类实现的组合框是由一个可编辑区(缺省时是一个文本区)和一个可选取项的下拉列表组成的。因此,我们采取把它与JList比较的方式来介绍JComboBox.
18.1 JComboBox与JList的比较
JList和ComboBox很相似,因为这两个组件都显示一个项列表。因此,它们都有扩展ListModel接口的模型。而且,这两个组件都有绘制器,这些绘制器通过实现ListCellBenderer接口来绘制列表单元。
但是,列表和组合框在施工方面还是有差别的。列表单是不可编辑的,但是组合框可以配备一个编辑器。JComboBox组件把编辑工作交给实现ComboBoxEdit接口的一个对象来处理。
列表支持三个选取模式,并把选取工作实现ListSelectionModel接口的一个对象来处理。组合框在一个时刻只有一个可选取的项,而且选取工作由组合框模型来处理。另一方面,组合框支持键选取,即在某项上按下一下键就可以选取这个项,但列表不能这样做。
18.2 JComboBox组件
例18-1 可编辑组合框和不可编辑组合框
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test extends JApplet {
private JCheckBox checkBox = new JCheckBox("Editable");
private JComboBox comboBox = new JComboBox();
public void init() {
Container contentPane = getContentPane();
comboBox.addItem("Top");
comboBox.addItem("Center");
comboBox.addItem("Bottom");
checkBox.setSelected(comboBox.isEditable());
contentPane.setLayout(new FlowLayout());
contentPane.add(checkBox);
contentPane.add(comboBox);
checkBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
comboBox.setEditable(checkBox.isSelected());
}
});
comboBox.getEditor().addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("here" +
comboBox.getSelectedItem());
}
});
}
public static void main(String args[]) {
final JFrame f = new JFrame();
JApplet applet = new Test();
applet.init();
f.setContentPane(applet.getContentPane());
f.setBounds(100,100,308,199);
f.setTitle("An Application");
f.setVisible(true);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
}
}
18.3 组合框模型
18.3.1 JComboBoxModel
18.3.2 MutableComboBoxModel
18.3.3 DefaultComboBoxModel
18.4 组合框单绘制器
例18-2 一个定制的列表单元绘制器
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class Test extends JApplet {
public void init() {
Container contentPane = getContentPane();
JComboBox combo = new JComboBox(new Object[] {
new Object[] { Color.gray, "gray" },
new Object[] { Color.orange, "orange" },
new Object[] { Color.red, "red" },
new Object[] { Color.blue, "blue" },
new Object[] { Color.yellow, "yellow" },
new Object[] { Color.magenta, "magenta" },
new Object[] { Color.black, "black" },
new Object[] { Color.green, "green" },
new Object[] { Color.lightGray, "lightGray"} });
combo.setRenderer(new ColorRenderer());
contentPane.setLayout(new FlowLayout());
contentPane.add(combo);
}
}
class ColorRenderer extends JLabel implements ListCellRenderer {
private static ColorIcon icon = new ColorIcon();
private Border
redBorder = BorderFactory.createLineBorder(Color.red,2),
emptyBorder = BorderFactory.createEmptyBorder(2,2,2,2);
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
Object[] array = (Object[])value;
icon.setColor((Color)array[0]);
setIcon(icon);
setText((String)array[1]);
if(isSelected) setBorder(redBorder);
else setBorder(emptyBorder);
return this;
}
}
class ColorIcon implements Icon {
private Color color;
private int w, h;
public ColorIcon() {
this(Color.gray, 50, 15);
}
public ColorIcon(Color color, int w, int h) {
this.color = color;
this.w = w;
this.h = h;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(Color.black);
g.drawRect(x, y, w-1, h-1);
g.setColor(color);
g.fillRect(x+1, y+1, w-2, h-2);
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public int getIconWidth() {
return w;
}
public int getIconHeight() {
return h;
}
}
18.5 组合框键选取管理器
18.5.1 使用缺省键选取管理
例18-3 使用缺省的键选取管理器
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class Test extends JApplet {
private JComboBox colorCombo = new JComboBox(new Object[] {
new Item(new Object[] { Color.gray, "gray" }),
new Item(new Object[] { Color.orange, "orange" }),
new Item(new Object[] { Color.red, "red" }),
new Item(new Object[] { Color.blue, "blue" }),
new Item(new Object[] { Color.yellow, "yellow" }),
new Item(new Object[] { Color.magenta, "magenta" }),
new Item(new Object[] { Color.black, "black" }),
new Item(new Object[] { Color.green, "green" }),
new Item(new Object[] { Color.lightGray, "lightGray"})
});
public void init() {
final Container contentPane = getContentPane();
colorCombo.setRenderer(new ColorRenderer());
contentPane.setLayout(new FlowLayout());
contentPane.add(colorCombo);
colorCombo.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
Item item = (Item)colorCombo.getSelectedItem();
String first = item.toString().substring(0,1);
showStatus("'" + first + "'" + " is for " + item);
}
});
}
}
class Item {
private Color color;
private String string;
public Item(Object[] array) {
color = (Color)array[0];
string = (String)array[1];
}
public Color getColor() { return color; }
public String toString() { return string; }
}
class ColorRenderer extends JLabel implements ListCellRenderer {
private static ColorIcon icon = new ColorIcon();
private Border
redBorder = BorderFactory.createLineBorder(Color.red,2),
emptyBorder = BorderFactory.createEmptyBorder(2,2,2,2);
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
Item item = (Item)value;
icon.setColor(item.getColor());
setIcon(icon);
setText(item.toString());
if(isSelected) setBorder(redBorder);
else setBorder(emptyBorder);
return this;
}
}
class ColorIcon implements Icon {
private Color color;
private int w, h;
public ColorIcon() {
this(Color.gray, 50, 15);
}
public ColorIcon(Color color, int w, int h) {
this.color = color;
this.w = w;
this.h = h;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(Color.black);
g.drawRect(x, y, w-1, h-1);
g.setColor(color);
g.fillRect(x+1, y+1, w-2, h-2);
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public int getIconWidth() {
return w;
}
public int getIconHeight() {
return h;
}
}
18.5.2 定制键选取管理器
例18-4 实现一个定制的键选取管理器
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class Test extends JApplet {
private ColorKeySelectionManager ksm =
new ColorKeySelectionManager();
private JComboBox colorCombo = new JComboBox(new Object[] {
new Item(new Object[] { Color.gray, "gray" }),
new Item(new Object[] { Color.orange, "orange" }),
new Item(new Object[] { Color.red, "red" }),
new Item(new Object[] { Color.blue, "blue" }),
new Item(new Object[] { Color.yellow, "yellow" }),
new Item(new Object[] { Color.magenta, "magenta" }),
new Item(new Object[] { Color.black, "black" }),
new Item(new Object[] { Color.green, "green" }),
new Item(new Object[] { Color.lightGray, "lightGray"})
});
public void init() {
final Container contentPane = getContentPane();
colorCombo.setRenderer(new ColorRenderer());
colorCombo.setKeySelectionManager(ksm);
contentPane.setLayout(new FlowLayout());
contentPane.add(colorCombo);
colorCombo.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
Item item = (Item)colorCombo.getSelectedItem();
String itemString = item.toString();
showStatus("'" + ksm.getSearchString() +
"'" + " is for " + itemString);
}
});
}
}
class Item {
private Color color;
private String string;
public Item(Object[] array) {
color = (Color)array[0];
string = (String)array[1];
}
public Color getColor() { return color; }
public String toString() { return string; }
}
class ColorRenderer extends JLabel implements ListCellRenderer {
private static ColorIcon icon = new ColorIcon();
private Border
redBorder = BorderFactory.createLineBorder(Color.red,2),
emptyBorder = BorderFactory.createEmptyBorder(2,2,2,2);
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
Item item = (Item)value;
icon.setColor(item.getColor());
setIcon(icon);
setText(item.toString());
if(isSelected) setBorder(redBorder);
else setBorder(emptyBorder);
return this;
}
}
class ColorIcon implements Icon {
private Color color;
private int w, h;
public ColorIcon() {
this(Color.gray, 50, 15);
}
public ColorIcon(Color color, int w, int h) {
this.color = color;
this.w = w;
this.h = h;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(Color.black);
g.drawRect(x, y, w-1, h-1);
g.setColor(color);
g.fillRect(x+1, y+1, w-2, h-2);
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public int getIconWidth() {
return w;
}
public int getIconHeight() {
return h;
}
}
class ColorKeySelectionManager
implements JComboBox.KeySelectionManager {
private String searchString = new String();
private long lastTime;
public int selectionForKey(char key,ComboBoxModel model) {
updateSearchString(model, key);
int start = getIndexAfter(model,getSelectedString(model));
int selection = search(model, start);
if(selection == -1 && start != 0)
selection = search(model, 0);
return selection;
}
public String getSearchString() {
return searchString;
}
private int search(ComboBoxModel model, int start) {
for(int i=start; i < model.getSize(); ++i) {
String s = getString(model, i);
int searchLength = searchString.length();
if(s.regionMatches(0,searchString,0,searchLength))
return i;
}
return -1;
}
private int getIndexAfter(ComboBoxModel model, String find) {
int size = model.getSize();
if(find != null) {
for(int i=0; i < size; ++i) {
String s = getString(model, i);
if(s.compareToIgnoreCase(find) == 0) {
return (i == size-1) ? 0 : i + 1;
}
}
}
return 0;
}
private String getString(ComboBoxModel model, int index) {
Item item = (Item)model.getElementAt(index);
return item.toString();
}
private String getSelectedString(ComboBoxModel model) {
Item item = (Item)model.getSelectedItem();
return item.toString();
}
private void updateSearchString(
ComboBoxModel model, char key) {
long time = System.currentTimeMillis();
if(time - lastTime < 500) searchString += key;
else searchString = "" + key;
lastTime = time;
}
}
18.5.3 程序式的键选取
例18-5 使用SwingUtilities.invokeLater()
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class Test extends JApplet {
private JComboBox charsCombo = new JComboBox(new Object[] {
new Character('g'), new Character('o'),
new Character('r'), new Character('b'),
new Character('y'), new Character('m'),
new Character('g'), new Character('l'),
});
private JComboBox colorCombo = new JComboBox(new Object[] {
new Item(new Object[] { Color.gray, "gray" }),
new Item(new Object[] { Color.orange, "orange" }),
new Item(new Object[] { Color.red, "red" }),
new Item(new Object[] { Color.blue, "blue" }),
new Item(new Object[] { Color.yellow, "yellow" }),
new Item(new Object[] { Color.magenta, "magenta" }),
new Item(new Object[] { Color.black, "black" }),
new Item(new Object[] { Color.green, "green" }),
new Item(new Object[] { Color.lightGray, "lightGray"})
});
public void init() {
final Container contentPane = getContentPane();
colorCombo.setRenderer(new ColorRenderer());
colorCombo.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
Item item = (Item)colorCombo.getSelectedItem();
Character first = new Character(
item.toString().charAt(0));
showStatus("'" + first.toString() + "'" +
" is for " + item);
}
});
charsCombo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
final Character c = (Character)
charsCombo.getSelectedItem();
colorCombo.selectWithKeyChar(c.charValue());
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Item item = (Item)
colorCombo.getSelectedItem();
JOptionPane.showMessageDialog(contentPane,
"'" + c.toString() + "'" +
" is for " + item.toString());
}
});
}
});
contentPane.setLayout(
new FlowLayout(FlowLayout.CENTER, 10, 35));
contentPane.add(new JLabel("Select a Character:"));
contentPane.add(charsCombo);
contentPane.add(colorCombo);
}
}
class Item {
private Color color;
private String string;
public Item(Object[] array) {
color = (Color)array[0];
string = (String)array[1];
}
public Color getColor() { return color; }
public String toString() { return string; }
}
class ColorRenderer extends JLabel implements ListCellRenderer {
private static ColorIcon icon = new ColorIcon();
private Border
redBorder = BorderFactory.createLineBorder(Color.red,2),
emptyBorder = BorderFactory.createEmptyBorder(2,2,2,2);
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
Item item = (Item)value;
icon.setColor(item.getColor());
setIcon(icon);
setText(item.toString());
if(isSelected) setBorder(redBorder);
else setBorder(emptyBorder);
return this;
}
}
class ColorIcon implements Icon {
private Color color;
private int w, h;
public ColorIcon() {
this(Color.gray, 50, 15);
}
public ColorIcon(Color color, int w, int h) {
this.color = color;
this.w = w;
this.h = h;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(Color.black);
g.drawRect(x, y, w-1, h-1);
g.setColor(color);
g.fillRect(x+1, y+1, w-2, h-2);
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public int getIconWidth() {
return w;
}
public int getIconHeight() {
return h;
}
}
18.6 组合框编辑器
例18-6 实现一个定制的组合框编辑器
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
public class Test extends JApplet {
private JComboBox comboBox =
new JComboBox(new Object[] {
new Item(new Object[] {Color.gray, "gray"}),
new Item(new Object[] {Color.orange, "orange"}),
new Item(new Object[] {Color.red, "red"}),
new Item(new Object[] {Color.blue, "blue"}),
new Item(new Object[] {Color.yellow, "yellow"}),
new Item(new Object[] {Color.magenta, "magenta"}),
new Item(new Object[] {Color.black, "black"}),
new Item(new Object[] {Color.green, "green"}),
new Item(new Object[] {Color.lightGray, "lightGray"}),
new Item(new Object[] {Color.white, "white"}),
});
public void init() {
Container contentPane = getContentPane();
comboBox.setRenderer(new ColorRendererer());
comboBox.setEditor(new ColorComboBoxEditor());
comboBox.setEditable(true);
contentPane.setLayout(new FlowLayout());
contentPane.add(comboBox);
}
}
class Item {
private Color color;
private String string;
public Item(Object[] array) {
color = (Color)array[0];
string = (String)array[1];
}
public Color getColor() { return color; }
public String toString() { return string; }
}
class ColorComboBoxEditor extends AbstractComboBoxEditor {
ColorIcon editorIcon = new ColorIcon();
JLabel editorLabel = new JLabel(editorIcon);
Item item;
JColorChooser colorChooser = new JColorChooser();
ActionListener okListener = new OKListener();
Dialog dialog = JColorChooser.createDialog(
null, // parentComponent
"Choose A Color",// title
true, // modal
colorChooser,
okListener,
null); // cancel listener
public ColorComboBoxEditor() {
editorLabel.setBorder(BorderFactory.createEtchedBorder());
editorLabel.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
dialog.setVisible(true);
}
});
}
class OKListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
item =
new Item(new Object[] {
colorChooser.getColor(), null});
fireActionPerformed(e);
}
}
public Component getEditorComponent() {
return editorLabel;
}
public Object getItem() {
return item;
}
public void setItem(Object itemToSet) {
item = (Item)itemToSet;
// cannot set the selected item in an editor's
// setItem method, or an infinite loop results
editorIcon.setColor(item.getColor());
editorLabel.setText(item.toString());
}
public void selectAll() {
// from ComboBoxModel interface: nothing to select
}
}
abstract class AbstractComboBoxEditor implements ComboBoxEditor {
EventListenerList listenerList = new EventListenerList();
public void addActionListener(ActionListener listener) {
listenerList.add(ActionListener.class, listener);
}
public void removeActionListener(ActionListener listener) {
listenerList.remove(ActionListener.class, listener);
}
protected void fireActionPerformed(ActionEvent e) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==ActionListener.class) {
((ActionListener)
listeners[i+1]).actionPerformed(e);
}
}
}
}
class ColorRendererer extends JLabel implements ListCellRenderer {
private ColorIcon icon = new ColorIcon();
public ColorRendererer() {
setOpaque(true);
setIcon(icon);
}
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
Item item = (Item)value;
icon.setColor(item.getColor());
setText(item.toString());
if(isSelected) {
setForeground(list.getSelectionForeground());
setBackground(list.getSelectionBackground());
}
else {
setForeground(list.getForeground());
setBackground(list.getBackground());
}
return this;
}
}
class ColorIcon implements Icon {
private Color color;
private int w, h;
public ColorIcon() {
this(Color.gray, 50, 15);
}
public ColorIcon(Color color, int w, int h) {
this.color = color;
this.w = w;
this.h = h;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(Color.black);
g.drawRect(x, y, w-1, h-1);
g.setColor(color);
g.fillRect(x+1, y+1, w-2, h-2);
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public int getIconWidth() {
return w;
}
public int getIconHeight() {
return h;
}
}
18.6.1 JComboBox属性
18.6.2 JComboBox事件
例18-7 处理选取事件
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test extends JApplet {
private JComboBox comboBox = new JComboBox();
public void init() {
Container contentPane = getContentPane();
comboBox.addItem("Top");
comboBox.addItem("Center");
comboBox.addItem("Bottom");
contentPane.setLayout(new FlowLayout());
contentPane.add(comboBox);
comboBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent event) {
int state = event.getStateChange();
String item = (String)event.getItem(), s;
if(event.getStateChange() == ItemEvent.SELECTED)
s = " selected";
else
s = " deselected";
JOptionPane.showMessageDialog(
comboBox, // parent component
item + s, // message
"JComboBox Selection", // title
JOptionPane.INFORMATION_MESSAGE); // type
}
});
}
}
例18-8 处理编辑事件
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test extends JApplet {
private JComboBox comboBox = new JComboBox();
private ComboBoxEditor editor = comboBox.getEditor();
public void init() {
Container contentPane = getContentPane();
comboBox.setEditable(true);
comboBox.addItem("Top");
comboBox.addItem("Center");
comboBox.addItem("Bottom");
contentPane.setLayout(new FlowLayout());
contentPane.add(comboBox);
editor.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String s = (String)editor.getItem();
showStatus("Item Edited: " + s);
}
});
}
}
18.6.3 JComboBox类总结
例18-9 手工显示一个组件框的弹出式菜单
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Test extends JApplet {
public void init() {
Container contentPane = getContentPane();
JButton button = new JButton("show popup");
final JComboBox combo = new JComboBox();
combo.addItem("first item");
combo.addItem("second item");
combo.addItem("third item");
combo.addItem("fourth item");
combo.addItem("fifth item");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
combo.showPopup();
}
});
contentPane.setLayout(new FlowLayout());
contentPane.add(button);
contentPane.add(combo);
}
}
18.6.4 AWT兼容
18.7 本章回顾