一如介绍其他程序的起始,我们都需要来一个HelloWorld来帮助我们入门,SWT的HelloWorld如下:
import org.eclipse.swt.widgets.*; public class HelloWorld { public static void main(String[] args) { Display display = new Display(); Shell shell = new Shell(display); shell.setText("Hello World"); shell.setSize(200, 100); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep (); } display.dispose (); } }
运行这个程序就会得到如下结果:
下面我讲逐一介绍这个程序所包含的内容。
- Display
这是一个顶层容器组件,类似于Container或Component的功能,它主要负责与底层的窗口系统之间的连接。在具体含义上,它代表"屏幕"。
一个Display可以包含多个Shell(也是容器组件,下面会介绍到)。
通常情况下,一个应用程序只含一个Display,即Display通常是一个单例组件(Singleton)。 - Shell
它表示位于"屏幕"上面的"窗口",是Composite组件和Control组件构成的组件树的根。
在我们的HelloWorld程序中,我们可以设置标题(setText()),设置大小(setSize()),然后通过open()方法来显示这个窗口。怎么样,感觉很像JFrame吧?其实功能上差不多。 - Composite
可以包含其它Composite和Control的容器 - Control
这是一个重量级(HeavyWeight)系统对象。像按钮(Button),标签(Label),表格,工具栏和树形结构这些组件都是Control的子类,Conposite和Shell也不例外。
2.1.1 消息循环
我们可以看到,上面的代码中有这样的语句:
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep ();
}
|
如果你像我一样是由Java语言起步的,那么你会对这个消息循环的代码感到比较陌生,毕竟在SWING中我们主要利用事件驱动模型而不这样利用类似于Windows程序设计中的消息循环的方法来处理事件。但是这段代码意义还算简单明了,就是反复的读取和分派(dispatch)事件,并在没有事件的时候把控制权还给CPU。
2.1.2 资源的释放
最后一条语句是display.dispose ();,这告诉我们操作系统的资源是由程序员显示释放的。资源的释放遵循以下两条规则:
1. 如果你创建了某个资源,那么你就有责任释放它。
2. 释放父组件资源的同时也释放了其子组件的资源。
2.1.3 标准构造函数
窗口组件被创建的时候必须伴随一个他的上层组件,例如,我要建立一个按钮就可以采用如下方法:Button button = new Button(shell, SWT.PUSH);
其中,Button的父组件Shell是必不可少的,这样就限定了我们生成组件的顺序。
第二个参数被称为"Style Bit",表示了这个组件的显示特性,每种特性占一位,如下例所示:
Text test=new Text(group, SWT.SINGLE|SWT.BORDER);
|
这条代码生成了一个单一的,有边框的文本框。这显然又与习惯了JavaBeans模型,总是用setXXX()来设置属性的我们不太适应--毕竟是IBM的东西啊,秉承了其产品不易上手的传统。
2.1.4 错误与异常
SWTError指的是不能修复的错误,以及一些操作系统错误。
SWTException指的是一些可恢复的错误以及无效的线程访问之类的错误。
IllegalArgumentException指可修复的错误或参数为null之类的错误。
2.1.5 Item
Item类是一个轻量级的系统对象,总是作为基本的单位元素与其他一些类配合使用。比如Tree中的元素即为TreeItem,Table的单位元素则是TableItem,而MenuItem就是Menu的基本单位元素了。
2.1.6 SWT的类阶层体系结构
最后让我们来整体认识一下整个SWT窗口组件的层次结构,如下所示:以上的部分给我们以整体的认识,即一个SWT引用程序应该怎么创建,其基本的运行规则和相关类的体系结构。我想我就不用再对每一个控件的API或使用方面费唇舌了,熟悉这些东西是体力劳动,而网上有很多例子可供参考。下面一节我将详细介绍有关SWT布局的相关知识。
相信对于组件的布局(Layout)大家都不会太陌生,它的存在就是提供给我们一种可以在组件位置移动或更改大小时重新绘制组件的机制。设置组件的布局我们可以采用Composite.setLayout()方法来实现。
每种布局都有其相应的数据(Layout Data),可以通过Control.setLayoutData()方法来进行关联。以下是一些布局类及其显示效果:
- FillLayout:让所有子组件等大小的"填满"整个面板空间。
FillLayout是最简单的一个布局类,它将所有窗口组件放置到一行或一列中,并强制他们的大小也相等。FillLayout不能外覆(wrap),也不能定制边框和距离。很显然这样的限制让这个布局类最适合作类似于计算器面板的布局,或者为Taskbar和Toolbar上面的按钮作布局使用。

RowLayout:类似于AWT中的FlowLayout,让所有组件按行排列,一行排不下就放到下一行。
RowLayout比FillLayout用得更广泛一些,原因很简单,就是RowLayout支持FillLayout所部支持的功能,例如能够外覆,能够修改边框和间距等等。另外,每一个位于RowLayout中的窗口组件都可以通过设定一个RowData类来指定其在RowLayout中的宽度和高度。
GridLayout: GridLayout是3个标准布局类中最有用的,但同时也是最复杂的--没办法,强大的功能必定伴随着一定程度的复杂性。通过GridLayout,一个Composite的子窗口组件被放置在一个网格(Grid)之中。GridLayout有很多配置字段,并且和RowLayout一样,每一个布局于其中的窗口组件都可以有一个与之相关联的布局数据类,称为GridData。GridLayout的强大功能是通过对于每一个窗口组件的GridData的灵活控制来实现的。
鉴于GridLayout的复杂性(原本我就怀疑它根本就不是为手工书写代码而设计的),我并不建议各位直接手动书写GridData,最好借助可视化的工具(如VI)来帮助我们完成用GridLayout进行的界面设计。这样我们只需要书写少量控制代码,就可以获得复杂的界面布局了。
FormLayout:如图所示
StackLayout:几乎完全等同于CardLayout的功能。
在SWT中,位置和大小的变化并非自动发生的。应用程序既可以在Composite子类的构造函数中指定初始位置和大小,也可以在一个改变窗口大小的监听器中用布局类来定位和改变Composite子类的大小。
下面的一幅图包含了我们将要讨论的有关布局的大部分细节。一个Composite类的可显示区域分为三个部分,分别是Location,clientArea和trim。Composite的大小就是clientArea和trim的区域之和。一个布局类(Layout)的主要功能就是管理Composite子组件的大小和位置。通过布局类,我们可以管理子组件之间的距离-即间距(Spaceing),子组件与布局边缘之间的距离-即边距(margin)。布局的大小同时也是Composite的clientArea的大小。
至此,关于SWT的基础部分就告一段落,希望能够给大家以一个对于SWT的总体认识。下面的部分将主要介绍SWT的弱项-绘图。JGraph的一个作者就表达了对SWT/JFace/Draw2D的不满,认为SWT在执行效率上并没有什么改善,而且缺乏一些有用的API实现。话虽如此,但SWT的基本绘图功能还是不错的,如果有足够的时间和耐心的话还是可以绘出想要的图形的。下面就让我们看看SWT如何绘制2D和3D图形。