SWT教程-1

[] 在新建的工程里导入SWT

一个完整的SWT程序

下面的代码是一个完整的SWT程序,该程序创建一个标准的Windows窗口应用程序。

import org.eclipse.swt.widgets.Display;

import org.eclipse.swt.widgets.Shell;

public class HelloSWT {

    public static void main (String[] args) {

        Display display = new Display();

        Shell shell = new Shell(display);

        shell.open();

        while (!shell.isDisposed()) {

            if (!display.readAndDispatch()) {

display.sleep();

}

        }

        display.dispose();

}

}

SWT能够运行在多种不同的平台上,它使用平台上的窗口组件作为程序的工作及显示方式。因此在Windows平台上开发的SWT程序可以运行在Linux之上,并且在Linux上运行时其外观使用Linux的窗口主题。

 

Widget

Widget既是SWT中所有窗口组件的抽象基类,也是SWT中一个非常重要的概念。在SWT应用程序中,窗口组件是用户与程序交互的接口。它是信息的载体。它将程序的数据呈现在图形化的窗口中,同时它自身包含一定的状态。在不同的状态下,其自身的显示也会有所不同。窗口组件还用于监听用户事件,它会根据鼠标和键盘事件改变其状态。

SWT使用平台窗口组件,因此当创建一个SWT Widget的对象时,与操作系统相关的组件将会被创建。当这些SWT对象被销毁时,相应的平台组件也会被释放。

1创建Widget

1列出了Widget类的构造函数。

1                                                         Widget类的构造函数

   

Widget(Widget parent, int style)

创建窗口组件对象。该组件的父亲为parent,该组件的行为和外观由style决定。

Widget类是一个抽象类,它不能够被实例化。但是大部分SWT窗口组件类都继承自该类,因此这里所说的Widget类的创建时特性适用于它的子类。在大多数情况下,创建一个Widget对象需要传递一个父Widget对象。该父亲窗口组件对其孩子组件的生命周期具有一定的控制。当父亲组件消亡时,其孩子组件也消亡。不同的组件类其允许的父亲组件有所不同。比如TabItem的父亲必须是TabFolderTreeItem的父亲可以是Tree或者TreeItem

创建Widget实例对象时需要传递的另一个参数是style,该参数限定了组件的行为和外观。比如在创建Tree组件时,可以使用SWT.SINGLE参数,该参数说明创建的树组件中不能够同时选中多个元素;当然也可以使用SWT. MULTI参数。

在创建Widget对象时,样式参数可以是单个值, 也可以是多个样式的组合。比如在创建Tree组件时,可以使用SWT.SINGLESWT.CHECK的组合,后者表示树中的每一个元素都有一个勾选框。当然,在创建Tree组件时可以传入SWT.MULTI | SWT.SINGLE,虽然这在逻辑上不成立,但是不会有任何编译错误。在样式矛盾的情况下,树组件会使用SWT.SINGLE

所有的样式都以常量的形式定义在org.eclipse.swt.SWT类中。

不同的组件有不同的样式,在SWTJava Doc中列出了每个SWT 组件所允许的样式。在SWT中,每个组件都能够应用其父亲组件所对应的样式。

2释放Widget

为了高效管理系统资源,SWT的设计中要求SWT程序直接管理这些资源。Widget类中提供了一个名为dispose()的方法,在SWT的开发过程中,会常和该方法打交道。该方法用于释放与组件相关的资源。

关于窗口组件的释放,有以下两个准则。

准则1 主动创建它则主动释放它

这个准则的含义是,当在程序中使用new创建了一个 组件对象,就应该调用dispose()方法来释放它。比如在HelloSWT程序的最后,display被释放就是通过调用dispose方法实现的。需要指出的是,display并不继承自Widget类,但是在组件释放的概念上,它们是一致的。

准则2 释放组件时其孩子组件也会被释放

按照准则1的概念,那么在HelloSWT程序中, 也应该调用Shell对象的dispose()方法来释放其孩子组件。其实不然,当释放一个组件时,其孩子组件也会被释放,比如在释放一个Tree组件 时,其中的各个元素(TreeItem组件)也会被自动释放,因此不需要主动调用这些孩子组件的dispose()方法。

当调用组件的dispose()方法时,与其对应的平台组件将被释放,但是此时该组件对象仍然存在。此时调用该对象的方法会有什么结果呢,如代码2所示。

代码2

import org.eclipse.swt.widgets.Display;

import org.eclipse.swt.widgets.Shell;

public class HelloSWT {

    public static void main (String[] args) {

        Display display = new Display();

        Shell shell = new Shell(display);

        shell.setText("HelloSWT");

        shell.open();

        while (!shell.isDisposed()) {

            if (!display.readAndDispatch()) display.sleep();

        }

        display.dispose();

        shell.setText("it is wrong!");

}

}

运行代码2,该程序能够正常启动并显示,但是当关闭程序时,会抛出SWTException异常,如代码3所示。

代码3

Exception in thread "main" org.eclipse.swt.SWTException: Widget is disposed

     at org.eclipse.swt.SWT.error(SWT.java:2942)

     at org.eclipse.swt.SWT.error(SWT.java:2865)

     at org.eclipse.swt.SWT.error(SWT.java:2836)

     at org.eclipse.swt.widgets.Widget.error(Widget.java:395)

     at org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:297)

     at org.eclipse.swt.widgets.Shell.open(Shell.java:815)

     at first.HelloSWT.main(HelloSWT.java:16)

因此当一个组件的dispose()方法被调用,该组件正常释放之后,就不能够再对该组件对象以及其孩子组件对象进行任何操作了。从理论上来说,SWT的设计所引发的该问题的确不怎么光彩,但是在实际开发中,这个问题非常容易避免。

 

Display

虽然Display类包含了众多与窗口组件相似的概念。比如生命周期、事件及其监听等。但是Display并不是Widget类的子类。Display类没有对应的窗口形式,它用于在SWT与窗口平台之间建立起一座桥梁。

Display类将SWT程序中相应的代码转换为操作系统平台的窗口调用,Display类的一个重要功能是维护一组事件监听器。当事件发生时(鼠标事件、键盘事件、选择事件等),Display会从操作系统获得事件队列,并根据事件类型触发相应的事件监听器。这个监听过程体现在readAndDispatch()方法上,如表2所示。

2                                                       Display的构造函数

   

   

boolean readAndDispatch()

从窗口系统的事件队列中读取事件。一次一件地触发相应的监听器。如果事件队列中还包含事件,返回true,否则返回false

boolean sleep()

允许用户界面暂时释放CPU资源。

任何SWT程序都必须拥有一个Display类的实例,在HelloSWT中,程序的第一步便是创建该对象,当没有事件时,通过调用sleep()方法让该用户界面释放CPU资源。

 

Shell

运行HelloSWT程序,可以看到一个标准的窗口程序,这个窗口就是Shell窗口组件。该组件作为容器“存放”应用程序的其他控制组件,比如LabelTextTree等。当创建这些控制组件时,通常都以Shell组件作为其父亲组件

[] Widget子类之间的继承关系与创建窗口组件时的父子关系是两个不同的概念。

Shell是一个窗口组件,它也是Widget类的一个子类。因此Shell组件遵从前文描述的有关窗口组件生命周期的概念,Shell类提供了多个构造方法,如表3所示。

 

 

 

3                                                         Shell的构造函数

   

Shell()

该构造函数相当于调用Shell(Display(null))。在这种情况下,Shell对象会创建在当前活动的display之上。如果没有活动display,则创建在默认display之上。

Shell(Display display)

Shell对象创建在display之上,使用Shell组件的默认样式(SWT.SHELL_TRIM)。

Shell(Display display, int style)

使用displaystyle样式创建Shell对象。

Shell(int style)

使用style样式,其他与Shell()构造函数同。

Shell(Shell parent)

parent作为Shell对象的父亲组件,以父亲组件的display作为其display,以SWT.DIALOG_TRIM为样式创建Shell对象。

Shell(Shell parent, int style)

采用style样式,其他与Shell(Shell parent)构造函数相同。

在创建Shell对象时,不提倡使用无Display对象的构造函数。即Shell()Shell(int style)。在创建Shell对象时,通常不需要特别指定Shell组件的样式。当没有父亲Shell作为参数时,一个常见的Shell组件将被创建,该组件包含“关闭”、“最大化”、“最小化”按钮、一个标题栏并具有改变窗口大小的功能。如果构造Shell时包含一个非空的父亲Shell,则创建的Shell样式与通常的对话框样式相似,该窗口包含标题栏、“关闭”按钮以及边框。表4Shell组件的样式列表。

4                                                              Shell的样式

   

   

BORDER

窗口使用边框。

CLOSE

在窗口右上角添加“关闭”按钮。

MIN

在窗口右上角添加“最小化”按钮。

MAX

在窗口右上角添加“最大化”按钮。

NO_TRIM

窗口没有“特殊样式”,该窗口没有边框,没有“关闭”、“最大化”、“最小化”按钮,不能修改其大小。

RESIZE

大小可修改。

TITLE

窗口包含标题栏。

DIALOG_TRIM

BORDER | CLOSE | TITLE的组合。

SHELL_TRIM

CLOSE | MIN | MAX | RESIZE | TITLE的组合。

Shell组件还包含一个称做“模式”的样式, 该样式用于决定是否阻拦该Shell组件依赖的display上的其他输入。该样式可以是APPLICATION_MODALMODELESSPRIMARY_MODALSYSTEM_MODALPRIMARY_MODAL样式允许Shell组件阻拦对其父亲组件的输入;APPLICATION_MODAL阻拦Shell组件依赖的display上的所有其他Shell组件的输入;SYTEM_MODAL样式阻拦当前系统中所有的向Shell组件的输入。

代码4是使用“模式”样式的一个例子。在这段代码中,创建完parentShell对象之后,以parentShell为父亲组件,创建了一个称为childShell的窗口组件。根据上文对构造函数的介绍,childShell也依赖于display对象。同时,当parentShell释放时,childShell也会得到释放。childShell的样式包含两个组合,前一个决定了childShell外观样式,后一个决定了childShell对输入事件的阻拦机制。

代码4

public class ParentAndChildDemo {

public static void main (String[] args) {

Display display = new Display();

Shell parentShell = new Shell(display,

SWT.SHELL_TRIM | SWT.BORDER);

parentShell.setText("Parent Shell");

       parentShell.open();

       Shell childShell = new Shell(parentShell, SWT.DIALOG_TRIM |

SWT.PRIMARY_MODAL);

       childShell.setText("Child Shell");

       childShell.open();

       while (!parentShell.isDisposed()) {

           if (!display.readAndDispatch()) display.sleep();

       }

       display.dispose ();

}

}

运行代码4,可以看到它在桌面上打开两个窗口组件,上层窗口对应childShell。此时无法单击下层窗口,因为对于下层窗口的所有输入都被childShell对应的窗口阻拦。如果在上面的代码中,将SWT.PRIMARY_MODAL去掉,则这种阻拦方式也就消失了。

[] 不同的平台对阻拦“模式”的支持有所不同。在这种情况下,SWT会进行相应的“向上向下兼容”。比如一些操作系统就不支持SYSTEM_MODAL,此时就会向下兼容,使用APPLICATION_MODAL

熟悉Shell的这些样式是非常重要的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值