Java Swing用户界面组件:复选框+ 滑块+组合框+边界+单选按钮
共 13350字,需浏览 27分钟
·
2022-06-12 10:59
选择组件
前面已经讲述了如何获取用户输入的文本。但是在很多情况下,可能更加愿意给用户几种选择而不是让用户在文本组件中输入数据。给一组按钮或者一列选项让用户做出选择。(这样也免去了检查错误的麻烦。)在本节中,将介绍如何编写程序实现复选框、单选按钮、选项列表以及滑块。
复选框
如果想要接收的输入只是“是”或“非”,就可以使用复选框组件。复选框自动地带有标识标签。用户通过点击某个复选框来选择相应的选项,再点击则取消选择。当复选框获得焦点时,用户也可以通过按空格键来切换选择。
图9-15所示的程序中有两个复选框,其中一个用于打开或关闭字体斜体属性,而另一个用于加粗属性。注意第二个复选框有焦点,这一点可以由它周围的矩形框看出。只要用户点击某个复选框,程序就会刷新屏幕以便应用新的字体属性。
复选框需要一个紧邻它的标签来说明其用途。在构造器中指定标签文本。
bold = new JCheckBox("Bold");
可以使用setSelected方法选定或取消复选框。例如:
bold.setSelected(true);
isSelected方法将返回每个复选框的当前状态。如果没有选择则为false,否则为true。
当用户点击复选框时将触发一个动作事件。通常,可以为复选框设置一个动作监听器。在下面程序中,两个复选框使用了同一个动作监听器。
actionPerformed方法查询bold和italic两个复选框的状态,并且把面板中的字体设置为常规、加粗、斜体或者粗斜体。
例9-5给出了复选框的全部代码。
例9-5 CheckBoxTest.java
javax.swing.JCheckBox 1.2
• JCheckBox(String label)
用给定的标签构造一个复选框,该标签初始化为“未选”。
• JCheckBox(String label, boolean state)
用给定的标签和初始化状态构造一个复选框。
• JCheckBox(String label, Icon icon)
用给定的标签与初始化为“未选”的图标构造一个复选框。
• boolean isSelected ( )
返回复选框状态。
• void setSelected(boolean state)
将复选框设置为新的状态。
单选按钮
在前一个例子中,对于两个复选框来说,用户可以选择一个、两个或者两个都不选。在很多情况下,我们需要用户只选择几个选项当中的一个。当用户选择另一个的时候,前一个就会自动地取消选择。这样一组框通常称为单选按钮组(radio button group),这是因为这些按钮的工作像收音机上的电台选择按钮。当按下一个按钮时,
前一个按下的按钮就自动地弹起。图9-16显示了典型的例子。这里允许用户在多个选择中选择字体的大小—小、中、大和超大—但是,每次只能选择一个选项。
在Swing中实现单选按钮组非常简单。为单选按钮组构造一个ButtonGroup类型的对象。
然后,把JRadioButton类型的对象添加到按钮组中。按钮组对象负责当新按钮被按下时取消前一个按下的操作。
如果按钮初始状态已选择,构造器的第二个参数为true,同时其他按钮构造器的这个参数为false。注意,按钮组仅仅控制按钮的行为,如果想把这些按钮组织在一起布局,需要把它们添加到容器中,如JPanel。
看一下图9-15和图9-16,会发现单选按钮的外观不同于复选框。复选框为正方形,并且如果被选择,该正方形中会出现一个对钩的符号。单选按钮是圆形,选择以后圈内出现一个圆点。
单选按钮的事件通告机制与任何其他按钮一样。当用户点击一个单选按钮时,该按钮产生一个动作事件。在例子中,定义了一个动作监听器用来把字体大小设置为新值:
对比这个监听器和复选框中的监听器。每个单选按钮都对应一个不同的监听器对象。每个监听器对象都非常明确它需要做什么—把字体尺寸设置为一个特定值。在复选框例子中,使用的是一种不同的方法。两个复选框共享一个动作监听器。这个监听器调用一个方法来检查两个复选框的当前状态。
对于单选按钮来说,能够使用同一种方法吗?可以试一下使用一个监听器计算尺寸,如
if (smallButton.isSelected()) size = 8;
else if (mediumButton. isSelected()) size = 12;
. . .
然而,我们更愿意使用独立的动作监听器对象,因为这样可以把尺寸值和按钮紧密地绑定在一起。
例9-6是一个用于选择字体大小的完整的程序,它演示了单选按钮的工作过程。
例9-6 RadioButtonTest.java
javax.swing.JRadioButton 1.2
• JRadioButton(String label, boolean state)
用给定的标签和初始状态构造一个单选按钮。
• JRadioButton(String label, Icon icon)
用给定的标签和图标构造一个初始化为“未选”的单选按钮。
javax.swing.ButtonGroup 1.2
• void add(AbstractButton b)
将该按钮添加到组中。
• ButtonModel getSelection( )
返回该按钮的按钮模型。
javax.swing.ButtonModel 1.2
• String getActionCommand( )
返回这个按钮模型的动作命令。
javax.swing.AbstractButton 1.2
• void setActionCommand(String s)
设置这个按钮及其模型的动作命令。
边界
如果在一个窗口中有多组单选按钮,那么就需要用可视化的形式明确地指出哪些按钮属于同一组。Swing提供了一组有用的边界(border)来解决这个问题。可以在任何继承了JComponent的组件上应用边界。最常见的是在一个面板周围设置边界,然后用其他用户界面元素(如单选按钮)来填充面板。
有几种不同的边界可供选择,但是使用它们的步骤完全一样。
1)调用BorderFactory的静态方法创建边界。下面是几种可选的风格(如图9-17所示):
• 凹斜面
• 凸斜面
• 蚀刻
• 直线
• 不光滑
2)如果愿意的话,可以给边界添加标题,具体实现方法是将边界传递给:
BorderFactory.createTitledBorder.
3)如果确实想将边框凸显出来,可以调用下列方法把几种边界组合起来使用:
BorderFactory.createCompoundBorder.
4)调用JComponent类中setBorder方法将结果边界添加到组件中。
例如,下面代码说明了如何把一个带有标题的蚀刻边界添加到一个面板上:
Border etched = BorderFactory.createEtchedBorder( )
Border titled = BorderFactory.createTitledBorder(etched, "A Title");
panel.setBorder(titled);
运行例9-7中的程序可以看到各种边界的外观。
不同的边界有着不同的用于设置边界的宽度和颜色的选项。详情请参看API注释。真正的边界爱好者欣赏这一点,有一个SoftBevelBorder类用于具有柔和拐角的斜面边界;有一个LineBorder类用于弄圆拐角。这些边界只能通过这些类的某个构造器构造,它们没有BorderFactory方法。
例9-7 BorderTest.java
javax.swing.BorderFactory 1.2
• static Border createLineBorder(Color color)
• static Border createLineBorder(Color color, int thickness)
创建一个简单的直线边界。
• static MatteBorder createMatteBorder(int top, int left, int bottom, int right, Color color)
• static MatteBorder createMatteBorder(int top, int left, int bottom, int right, Icon tileIcon)
创建一个用颜色或一个重复(repeating)图标填充的粗边界。
• static Border createEmptyBorder( )
• static Border createEmptyBorder(int top, int left, int bottom, int right)
创建一个空边界。
• static Border createEtchedBorder( )
• static Border createEtchedBorder(Color highlight, Color shadow)
• static Border createEtchedBorder(int type)
• static Border createEtchedBorder(int type, Color highlight, Color shadow)
创建一个具有3D效果的直线边界。
参数:highlight, shadow
用于3D效果的颜色
type EtchedBorder.RAISED和EtchedBorder.LOWERED之一
• static Border createBevelBorder(int type)
• static Border createBevelBorder(int type, Color highlight, Color shadow)
• static Border createLoweredBevelBorder( )
• static Border createRaisedBevelBorder( )
创建具有凹面或凸面效果的边界。
参数:type BevelBorder.LOWERED和BevelBorder.RAISED之一
highlight, shadow
用于3D效果的颜色
• static TitledBorder createTitledBorder(String title)
• static TitledBorder createTitledBorder(Border border)
• static TitledBorder createTitledBorder(Border border, String title)
• static TitledBorder createTitledBorder(Border border, String title, int justification, int position)
• static TitledBorder createTitledBorder(Border border, String title, int justification, int position, Font font)
• static TitledBorder createTitledBorder(Border border, String title, int justification, int position, Font font, Color color)
创建一个具有给定特性的带标题的边框。
参数:title 标题字符串
border 用标题装饰的边界
justification TitledBorder常量LEFT、CENTER、RIGHT、LEADING、TRAILING或
DEFAULT_JUSTIFICATION (left) 之一
position TitledBorder常量ABOVE_TOP、TOP、BELOW_TOP、ABOVE_BOTTOM、
BOTTOM、BELOW_BOTTOM或DEFAULT_POSITION (top) 之一
font 标题的字体
color 标题的颜色
• static CompoundBorder createCompoundBorder(Border outsideBorder, Border insideBorder)
将两个边界组合成一个新的边界。
javax.swing.border.SoftBevelBorder 1.2
• SoftBevelBorder(int type)
• SoftBevelBorder(int type, Color highlight, Color shadow)
创建带有柔和角的斜面边界。
参数:type BevelBorder.LOWERED和BevelBorder.RAISED之一
highlight, shadow
用于3D效果的颜色
javax.swing.border.LineBorder 1.2
• public LineBorder(Color color, int thickness, boolean roundedCorners)
用指定的颜色和宽度创建一个直线边界。如果roundedCorners为true,则边界具有圆拐角。
javax.swing.JComponent 1.2
• void setBorder(Border border)
设置这个组件的边界。
组合框
如果有多个选择项,使用单选按钮就不太合适了,其原因是占据的屏幕空间太大。这时可以选择组合框。
当用户点击这个组件时,选择列表就会下拉出来,用户可以从中选择一项(见图9-18)。
如果下拉列表框被设置成可编辑的(editable),可以像编辑文本域一样编辑当前的选项内容。正因为这个原因,这种组件被称为组合框(combo box),它把文本域的灵活性与一组预定义的选项组合起来。JComboBox类提供了组合框的组件。
调用setEditable方法可以编辑组合框。注意编辑只会影响当前项,而不改变列表内容。
在例子中,用户可以选择字体风格列表(Serif、SansSerif、Monospaced等)选择字体。用户也可以键入其他的字体。
调用addItem增加选项。在示例程序中,只在构造器中调用addItem,实际上可以在任何位置调用它。
faceCombo = new JComboBox( );
faceCombo.setEditable(true);
faceCombo.addItem("Serif");
faceCombo.addItem("SansSerif");
. . .
这个方法将字符串添加到列表结尾。可以使用insertItemAt方法指定新项在列表中的插入位置:
faceCombo.insertItemAt("Monospaced", 0); // add at the beginning
可以增加任何类型的项—组合框将调用每项的toString方法显示其内容。
如果需要在运行时删除某些项,可以使用removeItem或者removeItemAt方法,使用哪个方法将取决于参数提供的是要删除的选项还是位置。
faceCombo.removeItem("Monospaced");
faceCombo.removeItemAt(0); // remove first item
removeAllItems方法将立即移除所有的选项。
提示:如果需要往组合框中添加大量的选项,addItem方法的性能就显得很差了。取而代之的是可以构造一个DefaultComboBoxModel,并调用addElement方法进行加载,然后再调用JComboBox类中的setModel方法。
当用户从组合框中选择一个选项时,组合框就会产生一个动作事件。为了判断哪个选项被选择,可以在事件参数上调用getSource方法来得到发送事件的组合框的一个引用。接着调用getSelectedItem方法获取当前选择的项。需要把这个方法的返回值转化为合适的类型,通常是String型。
例9-8给出了完整的代码。
注意:如果希望持久性地显示列表而不是下拉列表,就应该使用JList组件。在卷II的第6章将介绍JList。
例9-8 ComboBoxTest.java
javax.swing.JComboBox 1.2
• void setEditable(boolean b)
参数:b 如果组合框域可编辑则为true,否则为false
• void addItem(Object item)
将一个选项添加到选项列表中。
• void insertItemAt(Object item, int index)
将一个选项插入到选项列表的指定位置。
• void removeItem(Object item)
从选项列表删除一个选项。
• void removeItemAt(int index)
删除指定位置的选项。
• void removeAllItems( )
从选项列表中删除所有选项。
• Object getSelectedItem( )
返回当前所选的选项。
滑块
组合框允许用户从一组离散值中进行选择。滑块允许进行连续值的选择,例如,选择从1~100的任何一个数值。
通常构造滑块的方法如下:
JSlider slider = new JSlider(min, max, initialValue);
如果忽略最小值、最大值和初始值,那么这三个选项分别默认为0、100和50。
如果需要一个垂直的滑块,可以调用如下的构造器:
JSlider slider = new JSlider(SwingConstants.VERTICAL, min, max, initialValue);
这个构造器构造了一个无格式的滑块,如图9-19上面所示。下面将看一下如何为滑块添加装饰。
当用户滑动滑块时,滑块的值就会在最小值和最大值之间变化。当值发生变化时,ChangeEvent事件就会向所有的改变监听器发出通知。为了得到这些改变的通知,需要调用addChangeListener方法并且安装实现了ChangeListener接口的对象。这个接口只有一个方法StateChanged。
在这个方法中,可以获取滑块的当前值:
public void stateChanged(ChangeEvent event){
JSlider slider = (JSlider) event.getSource( );int value = slider.getValue( );
. . .
}
可以通过显示标尺(tick)对滑块进行修饰。例如,在示例程序中,第二个滑块使用了如下的设置:
slider.setMajorTickSpacing(20);
slider.setMinorTickSpacing(5);
上述滑块在每20个单元的位置显示一个的大标尺,每5个单元的位置显示一个小标尺标记。
所谓单元值就是滑块值,而不是像素值。
这些代码只是设置了标尺标记。要将它们实际地显示出来,还需要调用:
slider.setPaintTicks(true);
大标尺和小标尺是独立的。例如,可以为每20个单元设置一个大标尺,同时每7个单元设置一个小标尺,但是这样设置,滑块看起来有可能非常凌乱。
可以强制滑块对齐标尺。在这种模式下,只要用户拖放滑块结束,滑块就会马上自动移到最近的标尺处。激活此模式需要调用:
slider.setSnapToTicks(true);
注意:“对齐标尺”行为与想象的工作过程并不太一样。在滑块真正对齐之前,改变监听器一直报告并不对应标尺的滑块值,如果点击滑块附近,滑块通常向点击方向移动一小段距离,“对齐标尺”的滑块并不移动到下一个标尺处。
可以给大标尺添加标尺标签(tick mark label),调用方法:
slider.setPaintLabels(true);
例如,对于一个范围在0~100的滑块,如果大标尺的间距是20,每个大标尺的标签就应该是0、20、40、60、80和100。
也可以提供其他标尺标记,如字符串或者图标(见图9-19)。这样做有些麻烦。需要填充一个键为Integer类型而值为Component类型的散列表(在JDK 5.0中,自动打包可以使这个过程容易很多)。然后调用setLabelTable方法,组件就会放置在标尺标记处。通常使用JLabel对象。下面代码说明如何把标尺标签设置为A、B、C、D、E和F。
Hashtable labelTable = new Hashtable( );
labelTable.put(0, new JLabel("A"));
labelTable.put(20, new JLabel("B"));
. . .
labelTable.put(100, new JLabel("F"));
slider.setLabelTable(labelTable);
关于散列表的详细介绍,参看卷II的第2章。
例9-9显示了如何创建用图标作为标尺标签的滑块。
提示:如果标尺标记或标签不显示,请检查确认调用了setPaintTicks(true)和etPaintLabels(true)。
忽略滑块移动的轨迹,调用:
slider.setPaintTrack(false);
图9-19中第四个滑块就没有轨迹。
第五个滑块是逆向的,调用:
slider.setInverted(true);
例9-9中的程序演示了所有不同视觉效果的滑块。每个滑块都安装了一个改变事件监听器,它负责把当前的滑块值显示到框架底部的文本域中。
例9-9 SliderTest.java
javax.swing.JSlider 1.2
• JSlider( )
• JSlider(int direction)
• JSlider(int min, int max)
• JSlider(int min, int max, int initialValue)
• JSlider(int direction, int min, int max, int initialValue)
使用给定的方向、最大值、最小值和初始化值创建一个水平滑块。
参数:direction SwingConstants.HORIZONTAL或SwingConstants.VERTICAL之一。默认为水平
min, max 滑块值的最小值、最大值。默认值为0~100
initialValue 滑块的初始化值。默认值为50
• void setPaintTicks(boolean b)
如果b为true显示标尺。
• void setMajorTickSpacing(int units)
• void setMinorTickSpacing(int units)
用给定的滑块单元的倍数,设置大标尺和小标尺。
• void setPaintLabels(boolean b)
如果b是true,显示标尺标签。
• void setLabelTable(Dictionary table)
设置用于标尺标签的组件。表中的每一个键/值对都采用new Integer(value)/component的格式。
• void setSnapToTicks(boolean b)
如果b是true,每一次调整滑块都将对齐到最近的标尺处。
• void setPaintTrack(boolean b)
如果b是true,显示滑块滑动的轨迹。
JSpinner组件
JSpinner是带有两个小按钮的文本域。当点击它时,可以增加或减少文本域的值(见图9-20)。
在微调控制器(spinner)中的值可以是数字、日期、来自列表的值以及任何可以用上一个和下一个决定值的序列。JSpinner类为前三种情况定义了标准的数据模型,还可以自定义数据模型来描述任意的序列。
在默认情况下,微调控制器管理整数,并且按钮点击增加1或减少1。通过调用getValue方法可以获取当前的值。此方法返回Object,需要将它转化为Integer,并得到包装后的值。
JSpinner defaultSpinner = new JSpinner( );
. . .
int value = (Integer) defaultSpinner.getValue( );
可以改变增量,让它不为1,还可以提供更大或更小的边界值。下面的微调控制器,初始值为5,边界值为0和10,增量为0.5:
JSpinner boundedSpinner = new JSpinner(new SpinnerNumberModel(5, 0, 10, 0.5));
有两个SpinnerNumberModel构造器,一个带int参数,另一个带double参数。一旦某个参数是浮点值,就会调用第二个构造器。这个构造器将值设置为Double对象。
微调控制器没有限定只能是数值类型,可以构造一个在任何值的集合中迭代的微调控制器。
只要将SpinnerListModel传递给JSpinner构造器即可。也可以用数组或者实现了List接口的类(像ArrayList)构造SpinnerListModel。在下面的示例程序中,微调控制器控制着所有可能的字体名称。
String[ ] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment( ).getAvailableFontFamilyNames( );
JSpinner listSpinner = new JSpinner(new SpinnerListModel(fonts));
然而,发现迭代的方向有点混乱,这是因为与用户使用的组合框刚好相反。在组合框中,较大的值在较小的值下面,所以可以用向下的键来得到较大的值。但是微调控制器将对数组的下标进行增量迭加,因此向上的键才能得到较大的值。在SpinnerListModel中没有提供逆转顺序的方法,然而可以使用一个临时的匿名子类实现这种结果:
试试这两个版本,看看哪个更合适。
微调控制器的另一个应用就是让用户增减日期。要想得到这样一个微调控制器,并初始化为今天的日期,需要调用:
然而,仔细看一下图9-20,就会发现微调控制器文本显示了日期和时间,如
这里显示的时间对于日期收集器来说没有任何用途。要想让微调控制器只显示日期有些难度,下面是一段修改代码:
使用同样的方法,可以得到一个日期收集器。利用SpinnerDateModel构造器指定一个Date,上下边界(null表示没有边界)和需要修改的Calendar域(比如Calendar.HOUR)。
如果想将增量修改为15分钟,标准SpinnerDateModel类就显得力不从心了。
可以在微调控制器中自定义微调控制器模型显示任意的序列。在我们的示例程序中,有一个微调控制器,可以在字符串“meat”的排列中循环。可以通过点击微调控制器按钮来获得20个排列的字符串“mate”、“meta”、“team”。
在自定义模型时,应该扩展AbstractSpinnerModel类,并定义下面四个方法:
getValue方法返回存储在模型中的值,setValue方法设置一个新值。如果新值不合适,就会抛出一个IllegalArgumentException异常。
警告:在调用setValue方法设置新值之后,必须调用fireStateChanged方法,否则微调控制器不会更新。
getNextValue和getPreviousValue方法返回当前值的下一个或者上一个值,如果到了边界则返回null。
警告:getNextValue和getPreviousValue方法不改变当前值。当用户点击微调控制器的向上箭头,将调用getNextVaule方法。如果返回值不为null,调用setValue进行设置。
在例9-10中,使用了一个标准算法决定前后顺序。在这里,算法细节并不重要。
例9-10显示了如何产生多种微调控制器类型。可以通过点击Ok按钮来查看微调控制器的值。
例9-10 SpinnerTest.java
javax.swing.JSpinner 1.4
• JSpinner( )
构造一个编辑整数的微调控制器,初始值为0,增量为1,没有边界。
• JSpinner(SpinnerModel model)
构造一个使用给定数据模型的微调控制器。
• Object getValue( )
得到微调控制器的当前值。
• void setValue(Object value)
尝试设置微调控制器的值。如果该模型不能接受该值,抛出IllegalArgumentException异常。
• void setEditor(JComponent editor)
设置用于编辑微调控制器的值的组件。
javax.swing.SpinnerNumberModel 1.4
• SpinnerNumberModel(int initval, int minimum, int maximum, int stepSize)
• SpinnerNumberModel(double initval, double minimum, double maximum, double stepSize)
这些构造器产生管理Integer或Double类型的值的数字模型。无边界的值使用Integer和Double类的常量MIN_VALUE和MAX_VALUE定义。
参数:initval 初始值
minimum 最小有效值
maximum 最大有效值
stepSize 每次微调的增量或减量
javax.swing.SpinnerListModel 1.4
• SpinnerListModel(Object[ ] values)
• SpinnerListModel(List values)
这些构造器产生从给定值中选出一个值的模型。
javax.swing.SpinnerDateModel 1.4
• SpinnerDateModel( )
构造一个日期模型,用今天的日期作为初始值,没有下边界与上边界(no lower or upperbounds)增量为Calendar.DAY_OF_MONTH。
• SpinnerDateModel(Date initval, Comparable minimum, Comparable maximum, int step)
参数:initval 初始值
minimum 最小有效值,如果不想要下边界则为null
maximum 最大有效值,如果不想要上边界则为null
step 日期域每一次微调的增量或减量。Calendar类的下述常量之一:
ERA、YEAR、MONTH、WEEK_OF_YEAR、WEEK_OF_MONTH、
DAY_OF_MONTH 、 DAY_OF_YEAR 、 DAY_OF_WEEK 、
DAY_OF_WEEK_IN_MONTH、AM_PM、HOUR、HOUR_OF_DAY、
MINUTE、SECOND或MILLISECOND
java.text.SimpleDateFormat 1.1
• String toPattern( ) 1.2
得到这个日期格式器的编辑模式。一种典型的模式是“yyyy-MM-dd”。有关模式的详细的信息请参看JDK文档。
javax.swing.JSpinner.DateEditor 1.4
• DateEditor(JSpinner spinner, String pattern)
为微调控制器构造一个日期编辑器。
参数:spinner 编辑器所属的微调控制器
pattern 与SimpleDateFormat相关的格式模式
javax.swing.AbstractSpinnerModel 1.4
• Object getValue( )
得到该模型的当前值。
• void setValue(Object value)
给模型设置一个新值。如果该值不可接受,则抛出IllegalArgumentException异常。当覆盖这个方法时,在设置新值之后应该调用fireStateChanged。
• Object getNextValue( )
• Object getPreviousValue( )
计算(但是不设置)该模型定义序列中的下一个或上一个值。
今天就讲到这里,喜欢的朋友可以转发关注一下!!!
明天给大家分享GUI应用程序中的下拉式菜单~~~~~~
本文就是愿天堂没有BUG给大家分享的内容,大家有收获的话可以分享下,想学习更多的话可以到微信公众号里找我,我等你哦。