我们最常用的图形构件基本都被包括在*.widgets包中。比如Button、Combo、Text、Label、Sash、Table等等。其中两个最重要的构件当数Shell和Composite。
Shell相当于应用程序的主窗口框架。Composite相当于SWING中的Panel对象,充当构件容器的角色。当我们想在一个窗口中加入一些构件时,最好使用Composite作为构件的容器,然后再去*.layout包找出一种合适的布局方式。SWT对构件的布局也采用了SWING或AWT中Layout和Layout Data结合的方式。在*.layout包中可以找到四种Layout和与它们相对应的布局结构对象(Layout Data)。在*.custom包中,包含了对一些基本图形构件的扩展。比如其中的CLabel,就是对标准Label构件的扩展,在它上面可以同时加入文字和图片,也可以加边框。StyledText是Text构件的扩展。它提供了丰富的文本功能,比如对某段文字的背景色、前景色或字体的设置。在*.custom包中也可找到一个新的StackLayout布局方式。
SWT对用户操作的响应,比如鼠标或键盘事件,也是采用了AWT和SWING中的Observer模式。在*.event包中可以找到事件监听的Listener接口和相应的事件对象。例如常用的鼠标事件监听接口MouseListener、MouseMoveListener和MouseTrackListener,及对应的事件对象MouseEvent。
*.graphics包中可以找到针对图片、光标、字体或绘图的API。比如可通过Image类调用系统中不同类型的图片文件。通过GC类实现对图片、构件或显示器的绘图功能。
Eclipse还针对不同的平台开发了一些富有针对性的API。例如,在Windows平台下,可以通过*.ole.win32包很容易地调用ole控件。这使Java程序内嵌IE浏览器、Word或Excel等程序成为可能。
更复杂的程序
下面这个程序拥有一个文本框和一个按键,当用户点击按键的时候,文本框显示一句欢迎信息。
为了文本框和按键有比较合理的大小和布局,这里采用了GradLayout布局方式。这种布局是SWT中最常用也是最强大的布局方式,几乎所有的格式都可能通过GradLayout完成。下面的程序也涉及了如何应用系统资源(Color)以及如何释放系统资源。
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class WelcomeDemo {
public WelcomeDemo() {
}
private void initShell(Shell shell) {
// 为shell设置标题
shell.setText("WelcomeDemo");
// 为shell设置布局对象
GridLayout sLayout = new GridLayout();
shell.setLayout(sLayout);
// 构造一个Composite组件作为文本框和按钮的容器
Composite panel = new Composite(shell, SWT.NONE);
// 为panel设置布局结构对象
// 让panel尽可能地占满shell
GridData pLayoutData = new
GridData(GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL
| GridData.FILL_BOTH);
panel.setLayoutData(pLayoutData);
// 为panel设置布局对象
// 文本框和按钮将按这个布局对象显示
GridLayout pLayout = new GridLayout();
panel.setLayout(pLayout);
// 为panel设置背景色
final Color pColor = new Color(Display.getCurrent(), 0, 0, 255);
panel.setBackground(pColor);
// 构造文本框
final Text text = new Text(panel, SWT.MULTI | SWT.WRAP);
// 为文本框设置布局结构对象
// 让文本框尽可能地占满panel
GridData tLayoutData = new
GridData(SWT.FILL, SWT.FILL, true, true);
text.setLayoutData(tLayoutData);
// 构造按钮
Button button = new Button(panel, SWT.PUSH);
button.setText("确定");
// 为按钮添加鼠标事件
button.addMouseListener(new MouseAdapter() {
public void mouseDown(MouseEvent e) {
// 当用户点击按钮时显示信息
text.setText("欢迎");
}
});
// 当主窗口关闭时触发DisposeListener
shell.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
// 释放panel背景色资源
pColor.dispose();
}
});
}
public static void main(String args[]) {
WelcomeDemo demo = new WelcomeDemo();
Display display = new Display();
Shell shell = new Shell(display);
demo.initShell(shell);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
线程问题
Java语言本身提供了多线程机制,这种机制对GUI编程来说是不利的。它不能保证图形组件操作的同步与串行化。SWT采用了一种简单而直接的方式去适应本地GUI系统对线程的要求:在SWT中,通常存在一个被称为“用户线程”的唯一线程。只有在这个线程中才能调用对组件或某些图形API的访问操作。如果在非用户线程中程序直接调用这些访问操作,那么就会抛出SWTExcepiton异常。但是SWT也在*.widget.Display类中提供了两个方法可以间接地在非用户线程中进行图形组件的访问操作。这是通过syncExec(Runnable)和asyncExec(Runnable)这两个方法实现的。例如:
// 此时程序运行在一个非用户线程中,并且希望在组件panel上加入一个按钮。
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
Button button = new Button(panel, SWT.PUSH);
button.setText("Push");
}
});
方法syncExec()和asyncExec()的区别在于前者要在指定的线程执行结束后才返回,而后者则无论指定的线程是否执行都会立即返回到当前线程。