3.2 SWT基本窗口组件
上一节介绍了SWT程序开发中的一些基础知识,本节将通过实例介绍SWT的基本窗口组件,它们简单易用,并且在实际开发中,会被经常用到。本节先介绍最简单的控制组件,包括Label、Text、Button等,这些组件通常使用在对话框中,当然也会直接布置在Shell中;在熟悉了这些组件后,再介绍一些相对复杂的组件,包括Combo、Menu等。
3.2.1 Label
Label是使用最广泛的窗口组件,打开任何一个对话框都能够看到它的存在。它用于在窗口中显示文本数据、图像以及作为分隔符使用。这里分隔符是指在图形界面中的一条横线或竖线,用于分隔不同的组件元素,如表3-5所示。
表3‑5 Label类的构造函数
|
构 造 函 数 |
描 述 |
|
Label(Composite parent, int style) |
Label组件的父亲组件必须是Composite类型 |
Composite也是Widget的一个子类,该类的设计遵从设计模式中的Composite模式。它能够存放其他的组件,后文中介绍到的Table以及Tree等组件,分别用来存放表格数据和继承结构的数据,它们都是Composite的子类。Shell类也是它的子类,因此Shell组件可以作为父亲放置Label组件,如表3-6所示。
表3‑6 类Label的样式
|
样 式 |
描 述 |
|
SEPERATOR |
该Label作为一个分隔符,此时不能向该Label对象设定文本或图片 |
|
HORIZONTAL |
当作为分隔符时,该分隔符为水平 |
|
VERTICAL |
当作为分隔符时,该分隔符为垂直 |
|
SHADOW_IN |
当作为分隔符时,该分隔符凹陷 |
|
SHADOW_OUT |
当作为分隔符时,该分隔符凸出 |
|
SHADOW_NONE |
当作为分隔符时,该分隔符无阴影 |
|
CENTER |
文本/图片在Label组件中居中 |
|
LEFT |
文本/图片在Label组件中居左 |
|
RIGHT |
文本/图片在Label组件中居右 |
|
WRAP |
该Label组件支持“包装”功能 |
表中前6个样式用于Label组件作为分隔符的情形,接下来的3个组件则是当该组件作为文本或图片的载体时,用来控制这些内容的位置。当Label中文本内容长度过长,其父亲组件内无法在一行内完全显示该内容时,Label组件会对该内容进行“包装”,比如换行显示等。
实例3-1 Label的使用
实例3-1显示如何在程序中使用Label组件,如代码3-5所示。读者目前可以忽略Layout对象,在3.4节中会详细介绍Layout的含义和功能。
代码 3-5
public class LabelEg {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell();
shell.setLayout(new GridLayout(1, false));
// 创建包含边界的Label对象
Label label1 = new Label(shell, SWT.BORDER);
// 该Label为文本Label
label1.setText("This is a text Label with border.");
// 创建作为水平分隔符的Label对象
Label label2 = new Label(shell, SWT.HORIZONTAL | SWT.SEPARATOR);
label2.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
Image image = new Image(display, "label.jpg");
// 创建作为图片容器的Label对象,该图片在Label中居中
Label imageLabel = new Label(shell, SWT.CENTER);
imageLabel.setImage(image);
imageLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
运行代码3-5,结果如图3-11所示。根据组件关联的Layout不同,其占用的空间也不相同。通过改变程序主窗口的大小,可以看出图片始终居于imageLabel组件的中部。Label属于静态控制组件,也就是说,用户无法通过鼠标单击或者选择Label中的内容,更无法使用键盘修改其中的内容。

图3-11 代码3-5的运行结果
3.2.2 Button
Button是非常常见的一个控制组件,比如消息对话框中的“Yes”、“No”按钮就是Button组件,用户通过Button按钮来触发一些事件。在SWT中,这种功能的Button称作Push Button。除了作为Push Button外,SWT的Button组件还有其他丰富的功能,比如图形用户界面中常见的Checkbox,Radio Button等功能,都能够用SWT的Button类来实现。与Label类相同,Button类的构造函数也需要两个参数,其中一个作为其父亲组件,该组件必须是Composite类型;另一个参数则是该Button的样式,通过这些不同的参数,Button类从功能上能够充当Push Button,Radio Button等,表3-7列出了Button类的样式类型,与其他样式相同,这些样式也都定义在org.eclipse.swt.SWT中。
1.样式
表3‑7 窗口组件Button的样式
|
样 式 |
描 述 |
|
ARROW |
该Button为箭头样式 |
|
CHECK |
创建一个Checkbox勾选框 |
|
PUSH |
创建一个Push Button |
|
RADIO |
创建一个Radio Button,一组Radio Button中只能有一个被选中 |
|
TOGGLE |
创建一个Toggle Button,它能够保存当前该Button是否是按下的状态 |
|
FLAT |
该Push Button的样式为扁平状 |
|
UP |
向上的箭头 |
|
DOWN |
向下的箭头 |
|
CENTER |
该Button上显示的文字居中 |
|
LEFT |
该Button上显示的文字居左,如果与ARROW样式同时使用,则表示向左指的箭头 |
|
RIGHT |
该Button上显示的文字居右,如果与ARROW样式同时使用,则表示向右指的箭头 |
SWT在设计过程中,将功能相似的控制组件设计为一个类,通过向这个类的构造函数传递不同的样式来改变组件的外观与状态,而不是通过继承的方式实现这些外观及功能上的细微差别。这种设计有效控制了组件的类型,避免了类继承层次过分深入。
实例3-2 不同样式的Button
实例3-2是使用Button类的一个例子,如代码3-6所示,shell对象的setLayout()方法用于设定shell窗口的布局。可以看出,创建不同的Button只要根据改变样式参数即可,因为PUSH、CHECK、RADIO等样式分别代表了不同的Button类型,因此这几个样式不能相互组合。必须注意,样式在创建Button时传递,此后就不能够再修改它的值了。
代码 3-6
public class ButtonEg {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new GridLayout(2, true));
// 创建两个Push Button
new Button(shell, SWT.PUSH).setText("Push 1");
new Button(shell, SWT.PUSH).setText("Push 2");
// 创建两个勾选框
new Button(shell, SWT.CHECK).setText("Checkbox 1");
new Button(shell, SWT.CHECK).setText("Checkbox 2");
// 创建两个Radio Button
new Button(shell, SWT.RADIO).setText("Radio 1");
new Button(shell, SWT.RADIO).setText("Radio 2");
// 创建两个Toggle Button
new Button(shell, SWT.TOGGLE).setText("Toggle 1");
new Button(shell, SWT.TOGGLE).setText("Toggle 2");
// 创建两个Flat Button
new Button(shell, SWT.FLAT).setText("Flat 1");
new Button(shell, SWT.FLAT).setText("Flat 2");
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
运行代码3-6,结果如图3-12所示,该程序显示了各个不同样式的Button组件在外观和工作方式上的不同。Push Button非常简单,它的目的就是触发选择事件;Checkbox和Radio Button常用于“属性”对话框中,用于显示用户对属性的配置。该程序具有两个Radio Button,这种情况在实际开发中不应该出现,因为总是可以使用一个Checkbox来替换两个Radio Button,这样做更节省屏幕空间。
当在Push Button上按下鼠标时,该按钮被重新绘制,它的状态看上去凹陷下去,此时释放鼠标按钮,则会触发一个选择事件。但是如果释放鼠标按钮是在按钮图形之外,则没有任何事件被触发,Push Button是无状态的。与Push Button不同,Checkbox、Radio Button和Toggle Button都具有选择状态,这些状态能够通过getSelection()方法获得,同时也能够通过setSelection(boolean) 方法进行设定,但是调用这个set方法不会触发选择事件,只有用户通过鼠标或键盘进行选择时,选择事件才会被触发。通常使用这个set方法对这些Button设定初始值。

图3-12 代码3-6的运行结果
2.事件
目前本书还没有对SWT的事件进行详细的介绍,这里给出选择事件的一个例子,说明事件的使用方法。在实际程序中,用户单击Push Button后,程序总是应该有所动作,也就是说,应该对Push Button的选择事件做出响应;而对于Checkbox和Radio Button则视情况而定。
实例3-3 监听Button的选择事件
代码3-7给出监听事件的实例,该实例中创建了两个选择事件监听器对象(SelectionListener),分别监听Push Button和Radio Button。程序通过setSelection(boolean)方法设定了Radio Button的初始值。
代码 3-7
public class ButtonEg2 {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, true));
// 创建Push Button,用于显示两个Checkbox的状态
final Button pb = new Button(shell, SWT.PUSH);
pb.setText("Display Checkbox Status");
// 创建两个Checkbox勾选框
final Button cb1 = new Button(shell, SWT.CHECK);
cb1.setText("Checkbox 1");
// 初始化该Checkbox为勾选状态
cb1.setSelection(true);
final Button cb2 = new Button(shell, SWT.CHECK);
cb2.setText("Checkbox 2");
// 创建两个Radio Button,第一个选中时,Push Button可点,
// 第二个选中时,Push Button被禁止
final Button rb1 = new Button(shell, SWT.RADIO);
rb1.setText("Enable Push");
rb1.setSelection(true);
final Button rb2 = new Button(shell, SWT.RADIO);
rb2.setText("Disable Push");
// Push Button必须有监听事件,该监听器获得Checkbox的当前状态,
// 并打印在控制台
pb.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
// getSelection()方法用于获得checkbox的选择状态
String status1 = cb1.getSelection() ? "selected"
: "not selected";
String status2 = cb2.getSelection() ? "selected"
: "not selected";
System.out.println("checkbox1: " + status1);
System.out.println("checkbox2: " + status2);
}
});
// 为rb1添加选择事件监听器,当其被选中时设定Push Button不可点
rb1.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
pb.setEnabled(rb1.getSelection());
}
});
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
运行代码3-7,结果如图3-13所示,该图显示了程序的初始状态。此时Push Button可以单击,Checkbox和Radio Button也都根据初始值选定。此时单击Push Button,会触发该按钮的选择事件,Display对象从操作系统获取该事件,并最终调用该事件的监听器对象的widgetSelected()方法。如果在该按钮上按下鼠标,并将鼠标移至按钮之外并释放按钮,不会有任何事件触发。以这两种方式单击“Display Checkbox Status”按钮,查看控制台的打印信息。

图3-13 代码3-7的运行结果
单击“Disable Push”Radio Button,此时Push Button呈灰色,如图3-14所示,这时无法单击“Display Checkbox Status”按钮。

图3-14 “Display…”按钮被屏蔽
另外注意,在代码3-7中,可以将“Enable Push”Radio Button的初始值设定为false,这样程序在运行时,Radio Button中被选择的是“Disable Push”按钮,但是Push Button仍然可单击,因为前文解释过,直接调用setSelection(boolean)方法不会触发选择事件。
SWT的窗口组件中,一些方法在含义上与窗口事件关联,比如这里的setSelection(boolean)方法与Button的选择事件关联,但是调用这些方法不会触发事件;而另一些方法,比如下文中的Combo组件,其setSelection(int index)方法则会触发选择事件,这一点,读者应注意。






