Toggle Buttons(三)
5.4 JCheckBox类
JCheckBox类表示切换组件,在默认情况下,这个组件在接近文本标签处显示了一个复选框图标,用于两状态选项选择。复选框使用一个可选的复选标记来显示对象的当前状态,而不是如JToggleButton保持按钮按下状态。对于JCheckBox,图标显示了对象的状态,而对于JToggleButton,图标则是标签的一部分,通常并不用于显示状态信息。JCheckBox与JToggleButton之间除了UI相关部分不同外,这两个组件是相同的。图5-5演示了在一个匹萨预定程序中复选框的样子。
JCheckBox是由几部分构成的。与JToggleButton类似,JCheckBox使用一个ToggleButtonModel来表示其数据模型。用户界面委托是CheckBoxUI。尽管ButtonGroup可以用来组合复选框,但是通常这并不合适。当多个JCheckBox组件位于一个ButtonGroup中时,他们的行为类似于JRadioButton组件,但是看上去是JCheckBox组件。由于可视化的原因,我们不应将JCheckBox组件放在ButtonGroup中。
现在我们已经了解了JCheckBox的不同部分,下面我们来了解一下如何来使用。
5.4.1 创建JCheckBox组件
JCheckBox有八个构造函数:
public JCheckBox() JCheckBox aCheckBox = new JCheckBox(); public JCheckBox(Icon icon) JCheckBox aCheckBox = new JCheckBox(new DiamondIcon(Color.RED, false)); aCheckBox.setSelectedIcon(new DiamondIcon(Color.PINK, true)); public JCheckBox(Icon icon, boolean selected) JCheckBox aCheckBox = new JCheckBox(new DiamondIcon(Color.RED, false), true); aCheckBox.setSelectedIcon(new DiamondIcon(Color.PINK, true)); public JCheckBox(String text) JCheckBox aCheckBox = new JCheckBox("Spinach"); public JCheckBox(String text, boolean selected) JCheckBox aCheckBox = new JCheckBox("Onions", true); public JCheckBox(String text, Icon icon) JCheckBox aCheckBox = new JCheckBox("Garlic", new DiamondIcon(Color.RED, false)); aCheckBox.setSelectedIcon(new DiamondIcon(Color.PINK, true)); public JCheckBox(String text, Icon icon, boolean selected) JCheckBox aCheckBox = new JCheckBox("Anchovies", new DiamondIcon(Color.RED, false), true); aCheckBox.setSelectedIcon(new DiamondIcon(Color.PINK, true)); public JCheckBox(Action action) Action action = ...; JCheckBox aCheckBox = new JCheckBox(action);
每一个构造函数都允许我们定制零个或是至多三个属性:标签,图标或是初始选中状态。除非特别指明,默认情况下并没有标签,而复选框的默认选中/未选中图标表现为未选中。
如果我们在构造函数中初始化图标,图标用于复选框未选中状态,而复选框选中时也使用相同的图标。我们必须或者是通过setSelectedIcon(Icon newValue)方法来初始化选中图标,或者是确保图标是状态相关的并更新自身。如果我们没有配置选中图标,也没有使用状态相关图标,则相同的图标会出现在选中与未选中状态。通常而言,不在选中与未选中状态之间变化其可视外观的图标并不是JCheckBox所要求的。
5.4.2 JCheckBox属性
在创建了JCheckBox之后,我们可以修改其属性。JCheckBox特定的两个属性覆盖了其父类JToggleButton的行为。第三个borderPaintedFlat属性是在JDK 1.3版本中引入的。其余的属性都是通过其父类JToggleButton继承而来的。
JCheckBox属性
属性名
|
数据类型
|
访问性 |
accessibleContext
|
AccessibleContext
|
只读 |
borderPaintedFlat
|
boolean
|
读写绑定 |
UIClassID
|
String
|
只读 |
borderPaintedFlat属性可以将复选图标的边框的观感显示为两维而不是三维。在默认情况下,borderPaintedFlat属性为false,意味着边框将是三维的。图5-6显示了平坦边框的样子,其中第一个,第三个,第五个的边框是平坦的,而第二个与第四个不是。观感可以选择忽略这些属性。然而,对于组件的渲染者,例如表格与树,这个属性是十分用的,因为他们只显示状态而不显示是否可以选中。Windows与Motif观感类型使用这个属性,而Metal(以及Ocean)则不使用这个属性。
正如所列出的构造函数所显示的,如果我们选择通过构造函数设置图标,则构造函数只为未选中的状态设置一个图标。如果我们希望复选框图标显示实际的正确状态,我们必须使用一个状态感知图标,或者是通过setSelectedIcon()为选中状态关联一个不同的图标。具有两个不同的可视状态表示是大多数用户希望JCheckBox所应用的,所有除非我们有特殊的理由,最好是遵循普通用户界面的设计约定。
图5-7所显示的界面底部的第四个按钮演示了JCheckBox的用法。复选框总是显示了选中状态。下图显示了选中Pizza,未选中Calzone,未选中Anchovies以及未选中Crust时的状态。
列表5-3演示了创建具有不同图标的JCheckBox组件的三种可用方法,其中一个使用状态感知图标。最后一个复选框显示了坏图标的用法。
package net.ariel.ch05; import java.awt.Color; import java.awt.Component; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.GridLayout; import java.awt.Image; import javax.swing.AbstractButton; import javax.swing.ButtonModel; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JCheckBox; import javax.swing.JFrame; import net.ariel.ch04.DiamondIcon; public class IconCheckBoxSample { private static class CheckBoxIcon implements Icon { private ImageIcon checkedIcon = new ImageIcon("plus.png"); private ImageIcon uncheckedIcon = new ImageIcon("minus.png"); public void paintIcon(Component component, Graphics g, int x, int y) { AbstractButton abstractButton = (AbstractButton)component; ButtonModel buttonModel = abstractButton.getModel(); g.translate(x, y); ImageIcon imageIcon = buttonModel.isSelected() ? checkedIcon : uncheckedIcon; Image image = imageIcon.getImage(); g.drawImage(image, 0, 0, component); g.translate(-x, -y); } public int getIconWidth() { return 20; } public int getIconHeight() { return 20; } } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Runnable runner = new Runnable() { public void run() { JFrame frame = new JFrame("Iconizing CheckBox"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Icon checked = new DiamondIcon(Color.BLACK, true); Icon unchecked = new DiamondIcon(Color.BLACK, false); JCheckBox aCheckBox1 = new JCheckBox("Pizza", unchecked); JCheckBox aCheckBox2 = new JCheckBox("Calzone"); aCheckBox2.setIcon(unchecked); aCheckBox2.setSelectedIcon(checked); Icon checkBoxIcon = new CheckBoxIcon(); JCheckBox aCheckBox3 = new JCheckBox("Anchovies", checkBoxIcon); JCheckBox aCheckBox4 = new JCheckBox("Stuffed Crust", checked); frame.setLayout(new GridLayout(0, 1)); frame.add(aCheckBox1); frame.add(aCheckBox2); frame.add(aCheckBox3); frame.add(aCheckBox4); frame.setSize(300, 200); frame.setVisible(true); } }; EventQueue.invokeLater(runner); } }
5.4.3 处理JCheckBox选中事件
与JToggleButton类似,我们也可以使用三种方法来处理JCheckBox事件:使用ActionListener,ItemListener或是ChangeListener。接受Action的构造函数只是添加一个参数作为ActionListener。
使用ActionListener监听JCheckBox事件
使用ActionListener订阅ActionEvent事件可以使得我们确定用户何时切换JCheckBox状态。与JToggleButton类似,所订阅的监听器会被通知选中,但并不会通知新状态。要确定选中状态,我们必须获取事件源的模型并进行查询,如下面的ActionListener源码所示。这个监听器修改了复选框的标签来反映选中状态。
ActionListener actionListener = new ActionListener() { public void actionPerformed(ActionEvent actionEvent) { AbstractButton abstractButton = (AbstractButton)actionEvent.getSource(); boolean selected = abstractButton.getModel().isSelected(); String newLabel = (selected ? SELECTED_LABEL : DESELECTED_LABEL); abstractButton.setText(newLabel); } };
使用ItemListener监听JCheckBox事件
与JToggleButton类似,对于JCheckBox而言,更为适合的监听器是ItemListener。传递给ItemListener的itemStateChanged()方法的ItemEvent事件包含复选框的当前状态。这使得我们可以进行正确的响应,而无需查询当前的按钮状态。
为了进行演示,下面的ItemListener依据选中组件的状态切换前景色与背景色。在这个ItemListener中,只有状态被选中时才会进行前景色与背景色的切换。
ItemListener itemListener = new ItemListener() { public void itemStateChanged(ItemEvent itemEvent) { AbstractButton abstractButton = (AbstractButton)itemEvent.getSource(); Color foreground = abstractButton.getForeground(); Color background = abstractButton.getBackground(); int state = itemEvent.getStateChange(); if (state == ItemEvent.SELECTED) { abstractButton.setForeground(background); abstractButton.setBackground(foreground); } } };
使用ChangeListener监听JCheckBox事件
与JToggleButton类似,ChangeListener也可以响应JCheckBox事件。当按钮被armed, pressed, selected, released时所订阅的ChangeListener会得到通知。另外,ChangeListener也会得到ButtonModel变化的通知,但是复选框的键盘快捷键。因为在JToggleButton与JCheckBox之间并没有ChangeListener的区别,所以我们可以将JToggleButton中的监听器关联到JCheckBox,而我们会得到相同的选中响应。
列表5-4中的示例程序演示了监听一个JCheckBox事件的所有监听器。为了演示ChangeListener会得到其他按钮模型属性变化的通知,我们将一个执键与组件相关联。由于ChangeListener的注册发生在mnemonic属性变化之前,所以ChangeListener会得到这个属性变化的通知。因为前景色,背景色与文本标签并不是按钮模型属性,ChangeListener并不会得到其他监听器所引起的这些属性变化的通知。
package net.ariel.ch05; import java.awt.BorderLayout; import java.awt.Color; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyEvent; import javax.swing.AbstractButton; import javax.swing.ButtonModel; import javax.swing.JCheckBox; import javax.swing.JFrame; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; public class SelectingCheckBox { private static String DESELECTED_LABEL = "Deselected"; private static String SELECTED_LABEL = "Selected"; /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Runnable runner = new Runnable() { public void run() { JFrame frame = new JFrame("Selecting CheckBox"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JCheckBox checkBox = new JCheckBox(DESELECTED_LABEL); ActionListener actionListener = new ActionListener() { public void actionPerformed(ActionEvent event) { AbstractButton abstractButton = (AbstractButton)event.getSource(); boolean selected = abstractButton.isSelected(); String newLabel = (selected ? SELECTED_LABEL : DESELECTED_LABEL); abstractButton.setText(newLabel); } }; ChangeListener changeListener = new ChangeListener() { public void stateChanged(ChangeEvent event) { AbstractButton abstractButton = (AbstractButton)event.getSource(); ButtonModel buttonModel = abstractButton.getModel(); boolean armed = buttonModel.isArmed(); boolean pressed = buttonModel.isPressed(); boolean selected = buttonModel.isSelected(); System.out.println("Changed: "+armed+"/"+pressed+"/"+selected); } }; ItemListener itemListener = new ItemListener() { public void itemStateChanged(ItemEvent event) { AbstractButton abstractButton = (AbstractButton)event.getSource(); Color foreground = abstractButton.getForeground(); Color background = abstractButton.getBackground(); int state = event.getStateChange(); if(state == ItemEvent.SELECTED) { abstractButton.setForeground(background); abstractButton.setBackground(foreground); } } }; checkBox.addActionListener(actionListener); checkBox.addChangeListener(changeListener); checkBox.addItemListener(itemListener); checkBox.setMnemonic(KeyEvent.VK_S); frame.add(checkBox, BorderLayout.NORTH); frame.setSize(300, 100); frame.setVisible(true); } }; EventQueue.invokeLater(runner); } }
SelectingCheckBox类在选中并取消选中后所产生的程序界面如图5-8所示。
5.4.4 自定义JCheckBox观感
每一个安装的Swing观感都会提供一个不同的JCheckBox外观与一个默认的UIResource值集合。图5-9显示了预安装的观感类型集合的JCheckBox组件外观:Motif,Windows,Ocean。第一,第三与第五个复选框为选中状态,而第三个具有输入焦点。
表5-4显示了JCheckBox的UIResource相关属性的集合。JCheckBox组件具有20个不同的属性。
JCheckBox UIResource元素
属性字符串 |
对象类型 |
CheckBox.background |
Color |
CheckBox.border |
Border |
CheckBox.darkShadow |
Color |
CheckBox.disabledText |
Color |
CheckBox.focus |
Color |
CheckBox.focusInputMap |
Object[] |
CheckBox.font |
Font |
CheckBox.foreground |
Color |
CheckBox.gradient |
List |
CheckBox.highlight |
Color |
CheckBox.icon |
Icon |
CheckBox.interiorBackground |
Color |
CheckBox.light |
Color |
CheckBox.margin |
Insets |
CheckBox.rollover |
Boolean |
CheckBox.select |
Color |
CheckBox.shadow |
Color |
CheckBox.textIconGap |
Integer |
CheckBox.textShiftOffset |
Integer |
CheckBoxUI |
String |