SWT(Standard Widget Toolkit)本身仅仅是Eclipse组织为了开发Eclipse IDE环境所编写的一组底层图形界面 API。或许是无心插柳,或许是有意为之,至今为止,SWT无论在性能上还是外观上,都超越了Sun公司提供的AWT和Swing
概述
SWT(Standard Widget Toolkit)是Eclipse中的窗口小部件工具箱,它是一组窗口组件的实现,并能底层操作系统图形用户界面平台紧密集成。另外,SWT定义了所有受支持平台上的公共可移植API,并尽可能地使用本机窗口小部件在每个平台上实现该API,这允许SWT在所有平台上维护一致的编程模型,且能立即反映底层操作系统图形用户界面外观中的任何更改。
JFace用来在 SWT 库顶部提供常见的应用程序用户界面功能。JFace并不试图“隐藏”SWT 或者替换它的功能。它提供一些类和接口,用来处理SWT对动态用户界面相关联的常见任务。
SWT/JFace是Eclispe的基础,Eclipse的Workbench就是建立在SWT/JFace之上的。另外,JFace是在SWT之上开发的,它和SWT形成一个交集,其中SWT提供最原始的组件,如图1所示。
JFace对SWT进行了扩展,把用户熟悉的一些组件进行了封装,在开发中用户可以尽可能地用JFace组件来开发自己的应用。JFace程序和SWT程序类似,只不过JFace把常用的功能进行了提炼,使用户不必太关心SWT的一些细节。
提示:SWT提供了一套API,它因为Eclipse而生,但它完全可以脱离Eclipse而存在。
基本特性
SWT是一个套库函数,它创建了Java 版的本地操作系统 GUI 控件。它依赖于本机实现,这意味着基于SWT的应用程序具有以下几个关键特性。
它们的外观、行为和执行类似于“本机”应用程序。
所提供的窗口小部件(Widget)反映了主机操作系统上提供的窗口小部件(组件和控件)。
主机 GUI 库的任何特殊行为都在 SWT GUI 中得到反映。
这些目标使得 SWT 不同于 Java 技术的 Swing,Swing 的设计目标是消除操作系统的差异。SWT 库反映了主机操作系统的基本窗口小部件,JFace 库有助于向 SWT 应用程序中添加大量服务,SWT 最重要的扩展之一是将应用程序的数据模型与显示及更改它的 GUI 隔离开来。
SWT中有如下一些基本的组件:
1. Widget:基本的 SWT GUI 组件(类似于 Java AWT 中的 Component 和 Swing 中的 JComponent),Widget 是一个抽象类。
2. Control:拥有操作系统的对等物的窗口小部件,Control 是一个抽象类。
3. Composite:包含其他控件的控件(类似于 Java AWT 中的 Container 和 Swing 中的JPanel)。
4. Item:其他控件包含的窗口小部件(该控件可能是复合控件),如列表和表。Item 是一个抽象类。
这些窗口组件(或小部件)被安排在继承层次结构中。其中Widget是底层的类,继承关系如图2所示
几乎所有SWT GUI都是从某些基础部分开始创建的。所有SWT窗口组件都可以在 org.eclipse.swt.widget 或 org.eclipse.swt.custom 包中找到(一些Eclipse插件还在其他包中提供了定制的窗口组件)。窗口组件包中包含一些基于操作系统控件的控件,而定制包中则包含一些超出操作系统控件集之外的控件。一些定制的软件包控件类似于窗口小部件包中的控件。为了避免命名冲突,定制控件的名称都是以“C”开始的(例如,比较 CLabel 与 Label)。
在SWT中,所有控件(除了一些高级控件,比如 shell)在创建的时候都必须有一个父控件(一个复合实例)。在创建的时候,这些控件被自动“添加”到父控件中,这与必须明确添加到父控件中的 AWT/Swing 中的控件有所不同,自动添加产生了一种“自上而下”地构造GUI的方法。这样,所有控件都可以采用一个复合父控件(或者一个子类)作为构造函数的参数。
大多数控件都有一些必须在创建时设置的标记选项,因此大多数控件还有另外一个构造函数参数,通常称为样式或风格,该参数提供了设置这些选项的标记。所有这些参数值都是 整型常量,并且都是在 org.eclipse.swt 包的 SWT 类中定义的。如果不需要任何参数,则可以使用 SWT.NONE 值。
提示:创建一个组件通常有两个参数,第一个为父组件,第二个组件的显示样式,例如:“Button button = new Button(shell, SWT.RADIO);”。
“Hello world”SWT程序
现在SWT所依赖的包已经加入到了项目的ClassPath中,SWT程序和Java的程序一样,也是通过main函数运行的,如例程1所示。
例程1 HelloWorldSwt.java
运行SWT应用
SWT程序的运行要通过JNI调用相应的操作系统控件,运行SWT程序和运行Java应用程序有点不同,在Eclipse中用户可以选择运行SWT程序(SWT Application)可以运行SWT程序,步骤如下:
1. 打开Java的默认视图,在“Hello world”程序的文件上单击鼠标右键。
2. 选择“SWT Application”菜单,如图6所示。
3. 单击“SWT Application”菜单运行,运行效果如图7所示。
HelloWorldSwt程序只创建了一个窗口(shell),读者可以把shell当作其它组件的父窗口,创建其它组件。
提示:在Eclipse3.3以后,运行SWT程序和运行Java程序是一样的。
JFace程序
JFace 是一个用户界面工具箱,它提供很难实现的、用于开发用户界面功能部件的 helper 类,JFace 在原始的窗口小部件系统的级别之上运行。JFace 使用户可以专注于实现特定插件的功能,而不必花费精力来处理底层窗口小部件系统或者解决几乎在任何用户界面应用程序中都很常见的问题。
“Hello world”JFace程序
JFace的应用程序相对来说更简单,它通过“ApplicationWindow”类实现应用,“ApplicationWindow”把和操作系统交互的细节封装起来了,用户只需要关心自己窗口的建立,程序代码如例程2所示。
例程2
其中,JFace的应用程序可以通过重载“createContents(Composite parent)”方法添加窗口的组件到parent组件中。
运行JFace的程序和运行SWT程序一样。
in details:
在介绍组件之前,有必要介绍一下Control类。Control类是一个抽象类,它是所有窗口组件(即在Windows中能获得句柄的部件)的基类。
Control类的继承关系
Control类是为继承而设计的,所有窗口组件都继承于Control类,如图1所示。
Control的一个实例代表Windows中的一个窗口组件,它中有窗口名柄属性,但是在程序中不能够直接访问。
Control类的常用方法
Control类提供了窗口组件中的常用方法,所有的窗口组件都可以调用Control类的方法,常用方法如下。
1. setBounds (int x, int y, int width, int height)
解释:设定窗口组件的位置,参数(x,y)为窗口组件左上角顶点的相对于父窗口坐标,(width,height)为窗口的宽度和高度。
示例:button.setBounds(40, 50, 100, 30)。
2. setEnabled (boolean enabled)
解释:设定窗口是否可用,参数enabled为true表示窗口可用,为false表示窗口禁用。
示例:button.setEnabled(false)。
3. setVisible (boolean visible)
解释:设定窗口是否可显示,参数visible为true表示窗口可显示,为false表示窗口不可显示。
示例:button.setVisible(false)。
4. setToolTipText (String string)
解释:设定鼠标指向窗口时的提示信息,参数string为提示信息的内容。
示例:button.setToolTipText("very good")。
5. setFont (Font font)
解释:设定窗口文字的字体,参数font为字体对象。
示例:button. setFont (font)。
6. setForeground (Color color)
解释:设定窗口的前景色,参数color为颜色对象。
示例:button. setForeground (color)。
7. setBackground (Color color)
解释:设定窗口的背景色,参数color为颜色对象。
示例:button. setBackground (color)。
8. setCursor (Cursor cursor)
解释:设定窗口的光标形状,参数cursor为光标对象。
示例:button.setCursor(new Cursor(null,SWT.CURSOR_WAIT));
9. Control (Composite parent, int style)
解释:窗口组件中的构造函数一般会调用Control类的构造函数,参数parent为当前构建的窗口的父窗口,style为当前构建窗口的样式(默认可以指定为SWT.NONE)。
示例:Button button = new Button(shell, SWT.NONE)。
另外,Control类还实现了一些和窗口有关的方法,例如createWidget和createHandle等,这些方法直接和操作系统相关,有兴趣的读者可以继续研究。
提示:并不是所有的组件调用Control的方法都有用,有些方法是为某些特殊的组件而存在的。
Composite是SWT中常用的组件,它的作用相当于一个容器面板,用户可以创建一个面板对象,通过面板对象来添加其他的子组件。
在GUI的开发中,为了布局的方便,常常用Composite来添加子组件,在Composite上设置相应的布局,从而使局部的布局效果不一样。一般来说面板可以设置成SWT.NONE的样式,另外还可以给Composite设置成带边框的样式。创建一个面板很简单,代码如例程1所示。
Composite是SWT中常用的组件,它的作用相当于一个容器面板,用户可以创建一个面板对象,通过面板对象来添加其他的子组件。
在GUI的开发中,为了布局的方便,常常用Composite来添加子组件,在Composite上设置相应的布局,从而使局部的布局效果不一样。一般来说面板可以设置成SWT.NONE的样式,另外还可以给Composite设置成带边框的样式。创建一个面板很简单,代码如例程1所示。
例程1 ComposizeExample.java
/**
* 为了节省篇幅,所有的import类已经被注释
* 读者可以通过ctrl+shift+o快捷键,自动引入所依赖的类
* 如果有问题可发邮件到[email protected]
* */
publicclass ComposizeExample {
publicstatic void main(String[] args) {
Displaydisplay = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
//创建面板
Composite composite1 = new Composite(shell,SWT.BORDER);
composite1.setLayout(newRowLayout(SWT.VERTICAL));
newButton(composite1, SWT.RADIO).setText("John");
new Button(composite1,SWT.RADIO).setText("Paul");
new Button(composite1,SWT.RADIO).setText("George");
newButton(composite1, SWT.RADIO).setText("Ringo");
Composite composite2 = new Composite(shell,SWT.NONE);
composite2.setLayout(new RowLayout(SWT.VERTICAL));
new Button(composite2,SWT.CHECK).setText("Barry");
new Button(composite2,SWT.CHECK).setText("Robin");
new Button(composite2,SWT.CHECK).setText("Maurice");
shell.setSize(200, 200);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
在SWT中,Group组件代表分组框,用户可以通过分组框把内容上相关的子组件组合在一起,例如某一类人、某一种水果等。
用户可以通过Group建立一个特定的分组,每一个分组有一个名称,可以通过Group的setText设置分组的显示名称,代码如例程2所示。
例程2 GroupExample.java
publicclass GroupExample {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
//添加分组框
Group group1 = new Group(shell,SWT.SHADOW_IN);
//设置分组框的显示标题
group1.setText("Who's yourfavorite?");
group1.setLayout(newRowLayout(SWT.VERTICAL));
new Button(group1,SWT.RADIO).setText("John");
new Button(group1,SWT.RADIO).setText("Paul");
new Button(group1,SWT.RADIO).setText("George");
newButton(group1, SWT.RADIO).setText("Ringo");
Group group2 = new Group(shell,SWT.NO_RADIO_GROUP);
group2.setText("Who's yourfavorite?");
group2.setLayout(newRowLayout(SWT.VERTICAL));
new Button(group2,SWT.CHECK).setText("Barry");
new Button(group2,SWT.CHECK).setText("Robin");
new Button(group2,SWT.CHECK).setText("Maurice");
shell.setSize(300, 200);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
以上程序创建了两个分组框,每个分组框都设定了相关显示标题,程序运行效果如图2所示。
图2 Group组件
Group组件和Composite组件的不同之处在于Group组件可以设置标题,用来表示分组的信息。
在很多应用程序中,由于信息量比较大,一页可能显示不下所有的信息,这就要求多页组件的支持。
在SWT中,通过TabFolder组织分页框,TabItem为每一个分页。创建一个分页框的步骤如下:
1. 在容器中创建一个TabFolder对象,例如“TabFolder tabFolder = newTabFolder(shell, SWT.BORDER);”。
2. 在TabFolder中创建一个TabItem对象,例如“TabItem tabItem = new TabItem (tabFolder, SWT.NULL);”。
3. 设置TabItem的显示标签,例如“tabItem.setText("Verygood");”。
4. 设置每一分页的Control对象(即在此页的顶层组件,一般是容器),例如“tabItem.setControl(composite);”。
为了更好地掌握分页框,下面通过一个实例演示如何创建分页框,代码如例程3所示。
例程3 TabFolderExample.java
publicclass TabFolderExample {
public static void main(String[] args) {
Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("Tab FolderExample");
shell.setSize(450, 250);
//创建分页框
final TabFolder tabFolder = newTabFolder(shell, SWT.BORDER);
for (int loopIndex = 0; loopIndex < 3;loopIndex++) {
//创建分页项
TabItem tabItem = new TabItem(tabFolder,SWT.NULL);
//设置分页项的标题
tabItem.setText("Tab " +loopIndex);
Text text = new Text(tabFolder,SWT.BORDER);
text.setText("This is page " +loopIndex);
//设置Control对象
tabItem.setControl(text);
}
TabItem tabItem = new TabItem(tabFolder,SWT.NULL);
tabItem.setText("Tab " + 3);
Composite composite = newComposite(tabFolder, SWT.BORDER);
Texttext = new Text(composite, SWT.BORDER);
text.setText("This is page " +3);
text.setBounds(10, 10, 100, 20);
//设置Control对象
tabItem.setControl(composite);
tabFolder.setSize(400, 200);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
以上程序创建了4个分页,其中第4个分页的Control对象为一个容器,程序运行效果如图3所示。
图3 TabFolder\TabItem组件
通常,每一个分页项都是一个容器组件,这样每一个分页就是一个容器,可以包含其它的组件。
SashForm是SWT中的分隔框组件,在容器中,有时需要调整容器中元素的大小,这就要用到SashForm。在SWT中添加分隔框的步骤如下:
1. 在容器中创建SashForm对象,例如“sashForm. = new SashForm(shell,SWT. HORIZONTAL);”。
2. 在SashForm对象中添加分隔项(即分隔框的子组件),可以是SashForm或Control的子类,例如“Text text1 = newText(sashForm, SWT.CENTER);”。
3. 设置SashForm中分隔项显示比例的权重(可选),例如“sashForm.setWeights(newint[]{1, 2, 3});”,表示3个分隔项之间的显示比例为“1:2:3”。
为了更好地掌握分隔框,下面通过一个实例演示如何创建分隔框,代码如例程4所示。
例程4 SashFormExample.java
publicclass SashFormExample {
Display display = new Display();
Shell shell = new Shell(display);
SashForm. sashForm;
SashForm. sashForm2;
public SashFormExample() {
shell.setLayout(new FillLayout());
//添加分隔框
sashForm. = new SashForm(shell,SWT.HORIZONTAL);
//添加分隔项
Text text1 = new Text(sashForm,SWT.CENTER);
text1.setText("Text in pane #1");
Text text2 = new Text(sashForm,SWT.CENTER);
text2.setText("Text in pane #2");
//添加子分隔框
sashForm2 = new SashForm(sashForm,SWT.VERTICAL);
final Label labelA = new Label(sashForm2,SWT.BORDER | SWT.CENTER);
labelA.setText("Label in paneA");
final Label labelB = new Label(sashForm2,SWT.BORDER |SWT.CENTER);
labelB.setText("Label in paneB");
//添加ControlListener监听器
text1.addControlListener(newControlListener() {
public void controlMoved(ControlEvent e){
}
public void controlResized(ControlEvente) {
System.out.println("Resized");
}
});
//设置分隔框中组件显示比例的权重
sashForm.setWeights(new int[]{1, 2, 3});
labelA.addMouseListener(new MouseListener(){
public void mouseDoubleClick(MouseEvente) {
if(sashForm2.getMaximizedControl() ==labelA)
sashForm2.setMaximizedControl(null);
else
sashForm2.setMaximizedControl(labelA);
}
public void mouseDown(MouseEvent e) {
}
public void mouseUp(MouseEvent e) {
}
});
shell.setSize(450, 200);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
// If no more entries in event queue
display.sleep();
}
}
display.dispose();
}
public static void main(String[] args) {
new SashFormExample();
}
}
以上程序中为嵌套的分隔框组件,第一层分隔项的显示比例为“1:2:3”,程序运行效果如图4所示。
图4 SashForm组件
SashForm和标签分隔符不同,SashForm分隔的几个组件大小可以通过SashForm调整。