使用
Eclipse
进行
SWT
编程
1.
为什么要使用
SWT?
SWT是IBM开发一套跨平台的GUI开发框架。为什么IBM要创建另一种GUI呢?为什么他们不使用现有的
Java
GUI框架呢?要回答这些问题,我需要回到
Java
的早期时代。
Sun已经创建了一套跨平台的GUI框架 AWT (Abstract Windowing Toolkit)。 这个AWT框架使用了本地窗口组件(native widgets)不过它存在LCD问题. 这个LCD问题导致了它失去主要的平台特性。换句话说,如果平台A有窗口组件1-40而平台B有窗口组件20-25,那么这个跨平台的AWT框架只能提供这两个集合的交集。
为了解决这个问题,Sun创建了一个新的框架使用模拟窗口组件(emulated widgets)来代替本地窗口组件(native widgets)。这个方法解决了LCD问题同时提供了丰富的窗口组件,不过也产生了其他的问题。例如,Swing应用程序不再和本地程序在样子上一致。虽然JVM有了很大的改善, 但是Swing应用程序仍然存在它们本地配对物所没有的性能问题。而且,Swing应用程序消耗了太多的内存,故不适合用于PDA和移动电话等小型设备。
IBM发现这些方法都无法满足他们的需求。因此,IBM创建了新的GUI库叫做SWT,它解决了AWT和Swing框架中的问题。SWT框架使用JNI访问本地窗口组件(native widgets),如果一个窗口组件在主机平台上不能获得,那么SWT会模拟这个不能获取的窗口组件。
2.
一个
SWT
应用程序的基础材料
Display, Shell和Widgets是一个SWT应用程序的基础材料。Displays用于管理事件循环(event loops)和控制UI线程和其他线程之间的通讯。Shell是应用程序中由
操作系统
窗体管理器来管理的窗体。任何SWT应用程序都需要至少一个Display实例和1个或更多的Shell实例。
图
1.
不同视角看的
SWT
程序
图
1
说明了一个SWT应用程序的不同看法。第一幅图是简化的UI对象的继承图。第二幅图是UI对象的包含结构。第三幅图就是创建了的UI。
如果一个应用程序使用多个线程,每个线程使用自己的Display对象实例。那么你可以通过使用静态的Display.getCurent()方法得到当前活跃的Display对象实例。
一个Shell表示一个特别操作系统中的一个窗口。一个Shell可以最大化,正常化,和最小化。有两种类型的shell。一种是顶层(top-level)Shell作为Display的主窗口创建的,另一种是依赖于其他shell的对话shell。
Shell的类型是由传给Shell构造函数的style位决定的。Shell的默认值是对话Shell。也就是说,如果没有传递任何值给构造函数参数,那么创建的是默认的对话Shell。如果一个Display对象作为参数,那么它是顶层(top-level)Shell。
有些窗口组件(widget)的属性必须在创建时设定。这些窗口组件(widget)属性叫做
style bits
。
Style bits
是在SWT类中定义的常量。如Button button = new Button( shell, <styleBits> )。当然可以通过或操作|来使用多个
style bit
。例如,要使用一个有边的按钮,你需要使用SWT.PUSH | SWT.BORDER作为style bit参数。
3.
环境设置
开发一个SWT应用程序与开发一个Swing应用程序不同。为了可以开始一个SWT应用程序的开发,你需要把SWT库加到classpath中,同时设置好对应的必要的环境变量。
第一个需要的库是swt.jar文件,它位于ECLIPSE_HOME/eclipse/plugins/org.eclipse.swt.win32_2.1.0/ws/win32目录。根据你使用的Eclipse版本,你可能需要使用不同的目录。这个swt.jar文件必须加到你的classpath中,为此到
Project->Properies->JavaBuildPath->Libraries->Add Variable -> Eclipse Home ->Extend
并按上述路径选择swt.jar库,然后单击
OK
。
然后,你可以编译SWT应用程序,但是由于抛出下边所示的运行时异常,无法运行它,因为swt.jar使用了本地库。你需要设置java.library.path环境变量来在Java中使用本地库。
java.lang.UnsatisfiedLinkError: no swt-win32-2133 in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1403)
at java.lang.Runtime.loadLibrary0(Runtime.java:788)
at java.lang.System.loadLibrary(System.java:832)
...
at org.eclipse.swt.widgets.Display.<init>(Display.java:287)
at Main.main(Main.java:25)
Exception in thread "main"
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class SliderExample
public static void main(String args[])
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout( new RowLayout());
// ------------------------
// Your code comes to here.
// ------------------------
shell.pack();
shell.open();
while( !shell.isDisposed())
if(!display.readAndDispatch())
display.sleep();
display.dispose();
5.
在
Eclipse
外运行
SWT
应用程序
要在不使用Eclipse的环境下运行SWT应用程序,swt.jar库必须在classpath中,并且java.library.path环境变量必须正确设置。根据主机平台,必须有合适的本地库存在。对于Windows平台,你可以根据如下来完成本地库的配置:
把swt.dll放在和程序相同的文件夹下。
把swt.dll放在JAVA_HOME/bin/文件夹下。
把swt.dll放在c:/windows/system32文件夹下。
javac -classpath c:/swt/swt.jar HelloWorld.java
Java -classpath c:/swt/swt.jar;. -Djava.library.path=c:/swt HelloWorld
java.library.path是JNI必需的环境变量。如果你没有设置这个环境变量。你的DLL 类是不能访问的。在这种情况下,应用程序不能正常的运行,并会抛出异常。
6. SWT
包(
Packages
)
SWT主要由下列包组成。这些包的定义是从Eclipse的API文档上得到的。你可以在Eclipse的网站上获得整个API文档。
org.eclipse.swt
:
包含了定义了SWT需要使用的常量和异常的类。这个包由三个类组成:SWT, SWTException和SWTError。SWT类可能是最受欢迎的类,因为它包含了SWT库所需要的常量如键盘、错误、颜色、布局、文本样式、按钮等常量。
org.eclipse.swt.widgets
:
包含了大多数核心SWT窗口组件,包括支持的接口和类。
org.eclipse.swt.events
:
定义了SWT组件使用的typed events, listeners和events。这个包有三组不同的类:Listener接口,Adapter类和Event类。
org.eclipse.swt.dnd
:
包含了对SWT窗口组件拖放(drag-and-drop)支持的类。
org.eclipse.swt.layout
:
包含了提供对SWT窗口组件自动安置和大小控制的类。
org.eclipse.swt.print
:
包含了对SWT窗口组件提供打印支持的类。
org.eclipse.swt.graphics
:
这个包提供了实现基本绘图操作需要的点,长方形、区域,颜色,光标,字体,图像上下文(GC)等的类和包含了显示图像代码和载入/保存他们的公有API的图像类。
7.
对话框
对话框的实现是本地的。也就是说,对话框像窗口组件一样是平台组件。SWT的Dialogs是从Dialog抽象类继承的。对话框不是窗口组件但是他可以容纳窗口组件。
图
2.
Dialog类层次图.
SWT有不同类型的对话框。有些对话框具有特殊的属性。Dialog类可以如源代码 2中使用
。
MessageBox messageBox =
new MessageBox(shell, SWT.OK|SWT.CANCEL);
if (messageBox.open() == SWT.OK)
System.out.println("Ok is pressed.");
每个对话框的open()方法返回不同的类型。例如, MessageBox对话框从open()方法返回int类型。因此,需要编写不同的条件来处理每一个对话框的返回值。
ColorDialog显示一个色彩选择调色板。它从return方法返回一个RGB对象。
DirectoryDialog使你可以选择一个目录。它从open()方法返回一个字符串。返回值就是选择的目录。当然,也可以设置额外的过滤器来过滤有些目录。
FontDialog使用户能够从系统所有的字体中选择一种字体。它从open()方法返回一个FontData对象。
FileDialog使用户能够选择一个文件。另外,可以设置扩展名过滤器,路径过滤器和文件名过滤器。对话框有如表1所示的样式:
图
3.
MessageBox
对话框
可用的按钮常量如下所列。使或操作可以完成不同按钮的联合。SWT框架按照style bits创建对话框。按钮常量有:SWT.ABORT, SWT.OK, SWT.CANCEL, SWT.RETRY, SWT.IGNORE,SWT.YES和SWT.NO。
表2 显示了对话框可以使用的图标。
8. Widgets
SWT GUI对象是从Widget和Control类继承而来的。Widget对象是基类定义了GUI类的通用方法。Control类是所有窗口GUI类的基类也就是说从Control类继承的组件需要一个窗口或者对话框来显示。
Menu对象也需要一个窗口来显示,但是这个需求间接得到了满足。一个Menu对象需要一个Control对象。
图
4.
Widget类层次图
图 4 显示了Widget的类层次图。Widget,Item,ScrollBar和Control类是抽象类。
8.1. Widget
事件
Widget事件总结表
3
。简化起见,表中只包含了事件名称。我们可以很容易的使用
<EventName>Event
想出事件类的名称。同样地,使用
<Listener Name>Listener
得到相关联地Listener地名称。并不是每一事件都有相配地Adapter类。所以,有adapter地事件用粗体表明。我们可以通过
<EventName>Adaptor
来得到对应地adapter名字。
例子:
事件名称是Control,事件类就是ControlEvent,listener类是ControlListener,adaptor 类是ControlAdaptor。
8.2.2
.
滑块(
Slider
)
,
标尺(
Scale
)和进度条(
ProgressBar
)窗口组件
标尺(Scale)表示一段可选择的连续值。范围可以用Scale类的setMinimum() 和setMaximum()方法设定。并可以使用getSelection()方法得到所选择的值。标尺在一次只有一个选择的值。也就是说,没有多选的可能。
图
6.
包含在一起的滑块和标尺
根据传递给构造函数的参数值的不同,我们可以创建不同的滑块和标尺。滑块和标尺常量如表5所示:
final Slider slider = new Slider(shell,SWT.VERTICAL);
slider.setMinimum(0);
slider.setMaximum(100);
slider.setIncrement(5);
slider.setPageIncrement(10);
slider.setSelection(25);
slider.addSelectionListener(
new SelectionAdapter()
public void widgetSelected(SelectionEvent e)
System.out.println("Selection:"+ slider.getSelection());
进度条组件类似于滑块和标尺组件,但是它不能被选择。它用于显示一个任务的进度。你可以对进度条组件使用SWT.SMOOTH and SWT.INTERMINATE常量。
8.2.3
.
文本窗口组件
一个文本窗口组件可以用于显示或者编辑文本。另外,你可以使用StyledText窗口组件来用不同的字体和颜色显示文本。StyledText窗口组件允许设置前景、背景色和指定范围文本块的字体。
图
7.
Text窗口组件
我们可以使用
表
6
所列的常量来创建Text窗口组件。因此,SWT.H_SCROLL和SWT.V_SCROLL常量可用于对Text窗口组件增加滚动条。
8.2.4
.
列表(
List
)窗口组件
List窗口组件可用于显示可选择的字符串列表。在选择的情况下,List对象会发送事件通告给它的listeners。这种类型的选择可以是单选,也可以是多选。选择的类型是由SWT.SINGLE和SWT.MULTI常量决定的。List窗口组件是可滚动的组件。因此SWT.H_SCROLL和SWT.V_SCROLL常量可用于给Text窗口组件增加滚动条。
图
8.
List 窗口组件
下边的代码片断显示了一个简单的List窗口组件。
List list = (List) e.getSource();
String[] str = list.getSelection();
for (int i = 0; i < str.length; i++)
System.out.println("Selection: "+str[i]);
图
10.
Composite可以容纳其他的组合类
组合类可以容纳其他的组合类。这种容纳关系是用一个组合窗口组件类的构造函数来建造的。与Swing相比,SWT没有add() 方法;作为代替,你必须使用构造函数来建立包容关系结构。
正如图10中所看到的,Shell类也是一个组合类。也就是说,Shell对象,可以容纳其他的组合类。
组合类是可以卷起的,也就是说可以使用SWT.H_SCROLL和SWT.V_SCROLL常量给组合窗口组件加上滚动条。
8.3.1
. Table
窗口组件
Table窗口组件可以显示一批字符串项或者图片。与其他的组合窗口组件相比,不能给table窗口组件增加组合控件。Table窗口组件的子构件必须是TableItem类型的。
图
11.
Table窗口组件
表7中的常量可以用于table窗口组件
TableItem item1 = new TableItem(table,0);
item1.setText(new String[]{"a","b"});
TableItem item2 = new TableItem(table,0);
item2.setText(new String[]{"a","b"});
table.setHeaderVisible(true);
table.setLinesVisible(true);
8.3.2
. Combo
(组合框)窗口组件
Combo窗口组件允许用户从值列表中选择一个值或者随意输入一个新值。组合框(combo)类似于列表组件,却使用了有限的空间。
虽然组合框是组合性质的,但是对它增加子元素是没有意义的。它的元素必须是String类型。一元素可以使用Combo类中定义的add(String element)方法来添加到组合框中。
图
12.
不同样式的组合框
下边的SWT常量可以用于Combo窗口组件:
8.3.3
. Tree
窗口组件
Tree窗口组件描绘了树中项的可选择层次结构。虽然Tree类是组合的,但是不能对它增加组合类对象。Tree类的子项必须是ThreeItem类型。
图
13.
不同样式的Tree窗口组件
下表是Tree组件常量的列表。
8.3.4
. TabFolder
TabFolder组件允许用户从一些页面中选择一页。虽然它是组合的,但是它不能增加其他的组合窗口组件。加到TabFolder的组件必须是TabItem类型。Tab的内容可以使用TabItem的setControl(Control control) 方法来设置。
图
14.
TabFolder窗口组件
一个简单的TabFolder例子:
new Label( tabFolder, SWT.BORDER);
label.setText( "Page " + i);
// add a control to the TabItem
item.setControl( label );
8.3.5
. CoolBar
窗口组件
CoolBar窗口组件提供了一个可以在动态摆放空间上增加项的区域。你可以增加一个或多个ToolBar组件到CoolBar上。一个CoolBar可一容纳一个或多个CoolItems。虽然是一个组合窗口组件,但是不能把其他组合类加到它上。CoolBar的子元素必须是CoolItem类型。
图
15.
Coolbar窗口组件
CoolBar窗口组件使用的例子:
new CoolItem(coolBar, SWT.NULL);
// set the control of the coolItem
coolItem.setControl(toolBar);
// You have to specify the size
Point size =
toolBar.computeSize( SWT.DEFAULT,
SWT.DEFAULT);
Point coolSize =
coolItem.computeSize (size.x, size.y);
coolItem.setSize(coolSize);