http://en.wikipedia.org/wiki/Eclipse_%28computing%29
package swtjfacesample;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

public class HelloSwt
{
/**//**
* Hello,world!
*
* @param args
*/
public static void main(String[] args)
{
Display display = new Display();
Shell shell = new Shell(display);
Text helloText = new Text(shell, SWT.CENTER);
helloText.setText("Hello,World!");
helloText.pack();
shell.pack();
shell.open();

while (!shell.isDisposed())
{
if (!display.readAndDispatch())
{
display.sleep();
}
}
display.dispose();
}
}
代码段1
Q:我的程序编译时候出现了错误!
A:如果是提示诸如Text,Display这些类不能够被成功引入,那么你需要检查一下是否我们前面提到的jar都已经被成功引入到你的classpath
Q:编译成功了但是不能运行,出现了异常
A:检查一下异常信息,如果你的异常信息类似这样:
Exception in thread "main" java.lang.UnsatisfiedLinkError: no swt-win32-3128 in java.library.path
...
的话,那说明我们在前面第三步提到的那些dll没有正常工作,最好能够按照前面的说明重新配置一下。
在这一节中,我们从前面所列举出来的Hello, world!程序开始对swt进行一些初步的探索。所谓的初步是指,我们会介绍编写swt程序的基本思路,以及对两个重要的类:Display和Shell作一些介绍。
因为这一节和前一节是分成两个部分贴出来的,所以我仍然将Hello, world!的代码段在下面列出来:
package swtjfacesample;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

public class HelloSwt
{
/**//**
* Hello,world!
*
* @param args
*/
public static void main(String[] args)
{
Display display = new Display();
Shell shell = new Shell(display);
Text helloText = new Text(shell, SWT.CENTER);
helloText.setText("Hello,World!");
helloText.pack();
shell.pack();
shell.open();

while (!shell.isDisposed())
{
if (!display.readAndDispatch())
{
display.sleep();
}
}
display.dispose();
}
}
代码段 2
这段程序虽然很简单,但是它反映了我们书写swt程序的步骤,这些步骤是:
1. 创建一个Display对象
2. 创建一个或者多个Shell对象,你可以认为Shell代表了程序的窗口。
3. 在Shell内创建各种部件(widget)
4. 对各个部件进行初始化(外观,状态等),同时为各种部件的事件创建监听器(listener)
5. 调用Shell对象的open()方法以显示窗体
6. 各种事件进行监听并处理,直到程序发出退出消息
7. 调用Display对象的dispose()方法以结束程序。
在Hello,world!程序中,为了让程序更加简单,我们没有创建事件监听器,在以后的内容中会进行专门介绍。
现在让我们稍微深入一些,看一下这些Display,Shell有什么作用以至于我们每个程序都必须有它们存在。
我们在前面说过,每个swt程序在最开始都必须创建一个Display对象。Display对象起什么作用呢?它是swt与操作系统沟通的一座桥梁。它负责swt和操作系统之间的通信。它将swt/JFace的各种调用转化为系统的底层调用,控制操作系统为swt分配的资源。同时我们也可以通过Display对象得到操作系统的一些信息。
Display是一个“幕后工作者”,它为swt/JFace提供支持,但是你并不能够从某个用户界面中看到它的影子。
在前面的Hello,world!程序中,我们可以看到构建一个Display对象是和普通的Java对象一样通过构造函数实现的。它为实现图形界面准备了最基本的条件。而在程序结束时我们必须显式地调用dispose() 方法来释放程序运行中所获得的资源。一般来说,一个程序只需要一个Display对象,当然没有人禁止你创建多个Display对象。但是在swt的javadoc中,我们可以看到关于这个问题一些描述:
“Applications which are built with SWT will almost always require only a single display. In particular, some platforms which SWT supports will not allow more than one active display. In other words, some platforms do not support creating a new display if one already exists that has not been sent the dispose() message.”
Display有着众多的方法,我们不可能一一介绍。在这里只挑选几个可能会比较常用的作一些简单介绍。
l setData()和getData():这一对函数允许我们为Display对象设定一些数据,setData()的参数中key和value类似于我们在使用Map对象中key和value的含义。
l getShells()得到关联到该Display对象的所有没有dispose的Shell对象
l getCurrent()得到与用户交互的当前线程
l readAndDispatch()得到事件并且调用对应的监听器进行处理
l sleep()等待事件发生
一个Shell对象就是一个窗口。你可以在上面放置各种部件创建丰富的图形界面。
我们都知道窗口有很多种,比如窗口有可以调整大小的,有不可以的,有的没有最大化最小化按钮。这些窗体的特征在swt中被成为风格(style)。一个窗体的风格可以用一个整数进行定义。这些风格的定义在org.eclipse.swt.SWT中。
Shell对象可用的风格包括:BORDER, CLOSE, MIN, MAX, NO_TRIM, RESIZE, TITLE , PLICATION_MODAL, MODELESS, PRIMARY_MODAL,S YSTEM_MODAL
这些风格我们不作一一介绍,你可以从他们字面意义看出一些含义来,当然也可以参考对应的javadoc。
Shell shell = new Shell(display,SWT.CLOSE | SWT.SYSTEM_MODAL);最后得到的窗体没有最大化和最小化按钮,并且大小是固定不变的。
因为swt运行于各种平台之上,而这些平台上的窗口管理器千差万别,所以所有这些风格都不是肯定可以实现的。在swt的javadoc中,这被称为暗示(hints)。
Shell对象的方法大都和GUI有关,比如setEnabled()设定了窗体是否能够和用户进行交互,setVisble()设定了窗体是否可见,setActive()将窗体设为当前的活动窗口。
我们可以用open()方法打开一个窗体,close()方法关闭一个窗体。
本节讨论了Display和Shell的一些概念,这是我们以后进一步了解swt的基础。在下一节中,我将介绍各种部件(widget)的用法,所谓部件,是指文本框,标签等UI实体。
大家好,五一已经过去了,你们玩得开心么?
在前面的两篇文章中,我向大家介绍了swt的一些基本知识,现在让我们继续下去讨论一下swt中的widget相关的一些知识以及介绍几种最为简单的widget。
Widget是Control的父类,而Control是我们使用的大多数部件的父类。我们在以前的一些编程语言中可能接触过“控件”或者“组件”之类的概念,部件(widget)的概念大体和这些相当。
在org.eclipse.swt.widgets中定义了众多的widget,甚至我们前面介绍的Shell也被当成widget的一种。
因为可用的widget如此之多,所以我大概没有办法全部一一介绍。在这一节中,我会介绍几种常用的widget。相信善于触类旁通的你通过这些极为简略的介绍应该可以开始使用各种widget,在使用中不断完善自己的认识。
首先我们来介绍Widget。它是一个抽象类,也是所有widget的父类。通过介绍这个类,我们可以得出这所有widget的一些共有特性。
Widget的方法中dispose()方法我们在以前曾经见到过,调用这个方法时候,所谓的接收者(receiver,譬如我们这样写:awidget.dispose(),那么awidget就是接收者,而这句话所处的对象成为调用者或者caller)和接收者中所包含的其他widget会释放它们所占用底层操作系统的资源。这也就是说你不必显式地为程序中创建的每个widget进行dispose()调用,而只需要确保最外层的widget(比如Display)进行了dispose()就可以了。
另外还可以通过isDisposed()判断是否该widget(接收者)已经进行了dispose。
Widget中的getStyle()方法得到widget的风格,而getDisplay()得到所处的Display对象。
atext.setData("title","I Have A Dream");
atext.setData("author","Martin Luther King");
代码段 3
在程序的其他部分可以用atext.getData(“title”)得到这篇文章的题目,或者用atext.getData("author")得到作者。
在前面我们提到过,Control是今后我们所使用大部分widget的父类。在这里我不单独进行介绍,而是在后面的部分中介绍。
和创建其他java object一样,我们通过使用new操作符创建部件的实例。有一点比较特殊的可能你需要使用带参数的构造函数进行new操作。类似下面的程序:
Text text=new Text(shell,SWT.CENTER);这种方法适用于几乎所有的widget,其中第一个参数是父widget,也就是指明了该widget需要被放置道另外哪一个widget之中,而第二个参数是这个widget的风格。
仅仅创建一个部件并不足以让你看到它,因为一个部件初始的长和宽都是0。你还需要设定它的大小。你可以用setSize()或者setBounds()方法手动设定部件的大小,也可以让系统自动调整部件的大小到一个合适的值,这个值也被成为首选尺寸(preferred size)。
可以通过调用pack()方法让系统调整控件大小。如果你希望系统自动调整,那么你需要首先设定控件需要表达的内容。举个例子来说,如果你的部件是一个文本框或者标签,你应该首先设定它所要显示的文本,这样系统可以通过文本的长度计算。
对于部件的位置,同样可以使用setLocation()或者setBounds()进行设定。
这里值得一提的是所谓的bounds,其实bounds可以看成是大小和尺寸的综合。比如setBounds(int x, int y,int width,int height)的参数中,x和y描述的是位置信息,而width和height描述了大小。
通过部件的setVisible方法可以控制部件进行隐藏或是显示。通过setEnabled方法可以控制部件是否有效。一个无效的部件不会对用户的任何动作作出响应。这两个方法的参数都是布尔型的。
可以通过setToolTipText()方法设定部件的提示文本。
标签用来显示静态的文本或者图像。关于图像和色彩我会在后面的部分进行介绍。
标签可以使用SWT.CENTER, SWT.LEFT, SWT.RIGHT中的一种指明文本的对齐方式(居中对齐,左对齐,右对齐)。
你也可以通过设置标签属性为SWT. SEPARATOR 使标签成为一条分隔符。

public class Labels
{

public static void main(String[] args)
{
Display display = new Display();
Shell shell = new Shell(display,SWT.SHELL_TRIM);
RowLayout layout=new RowLayout(SWT.VERTICAL);
shell.setLayout(layout);
shell.setText("Labels");
Label label1=new Label(shell,SWT.CENTER);
label1.setText("Label Demo");
Label label2=new Label(shell,SWT.SEPARATOR | SWT.HORIZONTAL);
shell.setSize(100,100);
shell.open();

while (!shell.isDisposed())
{
if (!display.readAndDispatch())
{
display.sleep();
}
}
display.dispose();
}
}
代码段 4
最后得到的效果可以参照下图:
图 4
Text就是最简单的文本框,与标签一样,我们可以通过设定它的风格来表示它的对齐方式(SWT.CENTER,SWT.LEFT,SWT.RIGHT),另外还有其他一些用于文本支持的方法,比如insert(),paster(),copy(),setSelection(),selectAll()等,这些方法在后面介绍swt事件模式会进行更详细的介绍。
在swt中,Button并不仅仅是按钮。构造时候定义的风格不同,所体现出的外观也不一样。
如果风格定义成SWT.PUSH,它就是一个普通的按钮。
如果定义为SWT.TOGGLE,它在被按下以后会保持按下的形状(而不会弹起来),直到鼠标再次在上面按一下才会回复弹起的形状。
如果风格定义为SWT.ARROW,它是一个带箭头的按钮,箭头的指向可以选择SWT.LEFT,SWT.RIGHT,SWT.UP,SWT.DOWN中的一个。
如果定义为SWT.CHECK,它是一个复选框。
如果定义为SWT.RADIO,它是一个单选框。
下面一段程序演示了各种不同的Button。

public class Buttons
{

public static void main(String[] args)
{
Display display = new Display();
Shell shell = new Shell(display,SWT.SHELL_TRIM);
RowLayout layout=new RowLayout(SWT.VERTICAL);
shell.setLayout(layout);
shell.setText("Buttons");
Button pushbutton=new Button(shell,SWT.PUSH | SWT.CENTER);
pushbutton.setText("SWT.PUSH");
Button togglebutton=new Button(shell,SWT.TOGGLE | SWT.LEFT);
togglebutton.setText("SWT.TOGGLE");
togglebutton.setSelection(true);
Button arrowbutton=new Button(shell,SWT.ARROW | SWT.LEFT);
Button checkbox=new Button(shell,SWT.CHECK);
checkbox.setText("SWT.CHECK");
Button radio=new Button(shell,SWT.RADIO);
radio.setText("SWT.RADIO");
radio.setSelection(true);
shell.pack();
shell.open();

while (!shell.isDisposed())
{
if (!display.readAndDispatch())
{
display.sleep();
}
}
display.dispose();
}
}
代码段 5
最后得到的窗口如下图:
图 5
在这一节中我向大家介绍了widget的一些基本知识,还有几种简单的widget。你可能注意到这些描述仅仅限于外观方面,如何让widget和用户交互起来呢?这需要我们处理各种用户事件,在下一节中我会向大家介绍swt的事件模式。
在向使用者提供最差的用户体验方面,中国的IT企业始终走在时代的最前端。之所以有这样的感慨其实是来源于往blog上贴上一节的内容:我用了一整天的功夫,不断与CSDN各种莫名其妙的出错提示进行斗争,最后终于成功的贴了上去。
其实作为CSDN blog一个使用者,我的要求并不高:只要能写blog,能够正常访问就可以了。然而就是这么一点基本的要求好像也得不到满足。
我不知道大家有没有这样的体验:其实软件使用者要求的东西都很基本,而现在软件做得越来越复杂,有相当大一部分是在于软件开发者把自己的注意力放在了一些附加功能(这些功能可能让用户感到惊喜,但是如果没有它们用户也不会不满意)上,而真正用户的要求却得不到满足。所以大家在设计程序的时候,一定要明白,有时候简单就是一种美,把时间花费到真正有价值的地方去。
OK,回到我们的主题上来。在这一节中,我将给大家介绍swt的事件模式。在前面我们也提到过,写一个swt程序,无非就是分几步走。其中比较需要费心的就是布置好用户界面和处理各种事件。
其实swt中处理事件非常简单,对应于各种事件都有相应的listener类,如果一种事件叫做Xyz,那么对应的listener类就是XyzListener。比如对应于鼠标事件的有MouseListener,对应于键盘事件的就是KeyListener。而在每种widget中,对于它可以处理的事件都有addXyzListener方法,只要把对应的listener实例作为参数传给它就可以了。
为了更加清楚的说明,我们先来看下面一段程序:
代码段 6

图 6
如果总结一下,我们可以得出处理事件的几个步骤:
1. 针对你所处理的事件,找出合适的XyzListener接口
2. 编写一个新的类,这个类实现了XyzListener接口
3. 在你所感兴趣的事件中编写处理代码,而对于那些你不感兴趣的方法可以让它们保持空白(就像实例中的widgetDefaultSelected()方法)一样
有时候我们可能会感觉这样仍然不够简单,比如我只对SelectionListener中的widgetSelected()方法感兴趣,但是为了能够通过编译器的编译,我却不得不写一个空白的widgetDefaultSelected()方法(因为SelectionListener是一个接口,你必须实现它所有的方法)。
幸运的是,swt帮我们解决了这个问题,途径就是使用adapter。在swt中,对应于一个XyzListener都有一个XyzAdapter,adapter都是抽象类并且实现了对应的listener接口,它为对应listener接口中的每个方法都定义了一个默认实现(基本上就是什么都不做),我们在使用时候只需要override掉自己感兴趣的方法就可以了。
结合上一小节中的代码,如果使用SelectionAdapter代替SelectionListener的话,我们的代码就可以这样写:
这样是不是很方便呢?
在处理各种事件时,我们需要一些附加信息,而EventObject给我们提供了这些信息。
我们先来看下面这个简单的小程序,在这段程序中,我们创建了两个文本框,当在第一个文本框输入时,第二个文本框中显示输入的字符。