本文主要讨论Java中的GUI图形库之一SWT/JFace在本文的第一部分将解释什么是SWT/JFace以及如何安装SWT/JFace在本文的第二部分将以实例的方式讨论如何使用SWT/JFace编写GUI程序 一 进入SWT/JFace世界 什么是SWT/JFace Java是一种强大的编程语言但强大就意味复杂尤其是和Java相关的名词就象天上的星星一样数都数不过来在本文中就涉及到两个比较常用的名词SWT和JFace在标题中将SWT和JFace放到一起并不是说SWT和JFace是一个意思而是说它们的关系非常紧密 基于Java的图形库最主要的有三种它们分别是SwingAWT和SWT其中前两个是Sun随JDK一起发布的而SWT则是由IBM领导的开源项目(现在已经脱离IBM了)Eclipse的一个子项目SWT的执行效率非常高这是由于SWT的底层是由C编写的由于SWT通过C直接调用系统层的GUI API因此使用SWT编写GUI程序在外观上就和使用C++Delphi(在Windows下)编写的程序完全一样它的这一点和AWT类似AWT在底层也是使用C直接调用系统层的GUI API但它们是有区别的最大的区别可能就是一个是Sun提供的一个是Eclipse自带的这就意味着如果使用AWT只要机器上安装了JDK或JRE发布软件时无需带其它的库而如何使用SWT在发布时必须要自带上SWT的*dll(Windows版)或*so(Linux/Unix版)文件以及相关的*jar包还有就是它们所提供的图形接口有一些差异SWT可能更丰富一些我们可以看看Eclipse的界面就知道了但随着Sun对AWT库的不断更新AWT的图形表现能力也在不断地提高 虽然SWT很强大但它比较底层也就是说它的一些功能在使用上还比较低级不太符合面向对象的特征因此在SWT的基础上又开发了JFaceJFace在SWT上进行了一定的扩展因此也可说JFace是基于SWT的就象在VC中使用MFC来包装Win API一样 SWT/Face的安装 在发布使用SWT/JFace编写的GUI程序时要随程序带上相应的库文件对于Windows版的SWT来说SWT包含有个dll文件和一个jar文件它们是swtawtwindllswtgdipwindllswtwglwindllswtwindll和swtjar在发布时要将个dll文件放到path路径中或者使用Djavalibrarypath设置相应的路径将swtjar放到classpath路径中或使用classpath设置相应的jar包而对于JFace除了上述的个文件外还要带上个jar包在点击提交按钮后将显示如图所示的页面 reruntime_jar orgeclipsejface_jar orgeclipsejfacetext_jar orgeclipseosgi_jar orgeclipsetext_jar 这个jar包都可以在eclipse的plugins目录中找到在这个文件后面的版本号可能会因为eclipse的版本号不同而不同但前面的部分都是一样的读者在找这些jar包时应注意这一点 SWT的开发包可以从单独下载也可以从eclipse的plugins目录复制而JFace的开发包并未提供单独的下载因此JFace的开发包必须要从plugins目录得到 二 让我们编写第一个程序吧 学习一种新技术的最好方法就是去使用它下面就让我们来使用SWT和JFace来分别实现同一个程序这个程序是一个简单的记事本程序在上面有三个按纽分别是新键打开保存下面是一个文本框用于编辑文本信息下面让我们先来看一下使用SWT实现的程序界面 图 使用SWT实现的记事本程序界面 怎么样看看上面的界面是不是和用DelphiVC做的界面完全一样!! 用SWT实现 不论一个程序带不带GUI都必须有一个入口点对于Java来说这个入口点就是main函数因此在编写程序之前我们必须定义一个类并且这个类中必须有个main函数 import orgeclipseswtwidgets*; import orgeclipseswt*; import orgeclipseswtevents*; import javaio*; public class FirstSWT { // 用于记录是否已经打开或保存了一个文件如果已经打开或保存了一个文件 // 这个变量就是这个文件的名子 private static String fn = ; public static void main(String[] args) { … … } } 上面四个import将导入一些在本程序中要用到的jar包前三个是SWT的包最后一个是Java的标准输入输出包 建立窗体 任何一个GUI程序都至少有一个窗体(在本程序中只有一个窗体)因此下面我们就在main函数中建立这个窗体 display = new Display(); shell = new Shell(display SWTDIALOG_TRIM); shellsetText(第一个SWT程序); shellsetSize( ); 在上面行代码中涉及到了两个类Display和Shell这两个类都是在FirstSWT中定义的私有静态类之所以定义成全局的是因为在以后的按钮事件类中要使用它们下面是它们的定义 private static Display display; private static Shell shell; 后面条语句通过调用Shell类的setText和setSize方法设置了窗口的标题和尺寸 下面解释一下Display和Shell类是什么 SWT在底层实现上分为两层系统层和用户层系统层就是直接和操作系统平台打交道系统层的存在依赖于操作系统平台在这里系统层就是Display类Display的功能就是在系统和用户之间架起一座桥梁也就是说使用户访问系统资源透明化而Shell类是直接和用户打交道因此它属于用户层通过Shell类可以控制窗体中的控件窗体本身的属性等而Shell通过Display这座桥梁访问系统级API l 向窗体中添加控件 接下来我们先在这个窗体上建立三个按钮代码如下 Button newButton = new Button(shell SWTPUSH); newButtonsetLocation( ); newButtonsetSize( ); newButtonsetText(新建); Button openButton = new Button(shell SWTPUSH); openButtonsetLocation( ); openButtonsetSize( ); openButtonsetText(打开); Button saveButton = new Button(shell SWTPUSH); saveButtonsetLocation( ); saveButtonsetSize( ); saveButtonsetText(保存); 按钮类是Button在建立时Button需要两个参数一个是Shell对象另外一个是按钮的类型在本例中我们使用SWTPUSH类型(一般的按钮类型) 注和SWT相关的常量都定义在了SWT 中 后面条语句分别设置了三个按钮的位置尺寸和按钮标题 最后在个按钮下方建立一个文本框 text = new Text(shell SWTMULTI | SWTBORDER | SWTV_SCROLL | SWTWRAP); textsetLocation( ); textsetSize(shellgetClientArea()width shellgetClientArea()height ); 文本框的类是Text和按钮不同的是由于文本框需要在按钮事件中被访问因此文本对象必须定义成全局的 private static Text text; 添加控件事件代码 现在让我们为三个按钮控件中加入事件代码和大多数语言不同的是按钮的单击事件不叫Click而叫Selection一般需要将Selection事件代码放到一个从SelectionAdapter类继承的子类中然后通过按钮类的addSelectionListener方法将这个事件类的实例传入按钮类的实例中但为了简便起见我们使用隐式建立对象的方法来建立事件类的对象下面是新建按钮的事件代码 newButtonaddSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { fn = ; shellsetText(第一个SWT程序); textsetText(); } }); 由于SelectionAdapter是一个抽象类它有一个抽象方法widgetSelected在上述代码被override了在新建按钮中将全局文件名赋成空串并将窗体的标题赋成初始状态最后将文本框清空 接下来让我们看看打开按钮的事件代码 openButtonaddSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { FileDialog dlg = new FileDialog(shell SWTOPEN); String fileName = dlgopen(); try { if (fileName != null) { // 打开指定的文件 FileInputStream fis = new FileInputStream(fileName); textsetText(); BufferedReader in = new BufferedReader(new InputStreamReader(fis)); String s = null; // 将指定的文件一行一行地加到文本框中 while ((s = inreadLine()) != null) textappend(s + \r\n); } if (fileName != null) { fn = fileName; shellsetText(fn); MessageBox successBox = new MessageBox(shell); successBoxsetText(信息); successBoxsetMessage(打开文件成功!); successBoxopen(); } } catch (Exception e) { MessageBox errorBox = new MessageBox(shell SWTICON_ERROR); errorBoxsetText(错误); errorBoxsetMessage(打开文件失败!); errorBoxopen(); } } }); 上面代码的基本逻辑是使用打开对话框选择一个文件使用FileInputStream将这个文件打开并且将文件中的内容一行一行地加入到文本框中如果这个过程失败显示错识对话框如果成功将fn变量和窗体的标题栏都赋成这个文件名 最后让我们实现保存按钮事件的代码 saveButtonaddSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { try { String fileName = null; if (fnequals()) { FileDialog dlg = new FileDialog(shell SWTSAVE); fileName = dlgopen(); if(fileName != null) fn = fileName; } if (fn != ) { FileOutputStream fos = new FileOutputStream(fn); OutputStreamWriter out = new OutputStreamWriter(fos); outwrite(textgetText()); outclose(); shellsetText(fn); MessageBox successBox = new MessageBox(shell); successBoxsetText(信息); successBoxsetMessage(保存文件成功!); successBoxopen(); } } catch (Exception e) { MessageBox errorBox = new MessageBox(shell SWTICON_ERROR); errorBoxsetText(错误); errorBoxsetMessage(保存文件失败!); errorBoxopen(); } } }); 这段代码的基本逻辑是如果当前已经打开一个文件或已经将当前的新建文件保存过了在点击保存按钮时不再显示保存对话框而直接将文件保存否则将显示一个保存对话框通过这个对话框可以选择一个文件名然后再保存 让我们最后画龙点睛吧 程序到这已经基本完成了但还需要进行最后一步就是对事件进行监听在main函数的最后可以加上如下的代码实现这个功能 shellopen(); // 显示窗体 while (!shellisDisposed()) // 当窗体未被关闭时执行循环体内的代码 { // 如果未发生事件通过sleep方法进行监视事件队列 if (!displayreadAndDispatch()) { displaysleep(); } } displaydispose(); // 释放底层的资源 看看上面的代码是不是有点象MFC的监听事件代码!! 用JFace实现 使用JFace实现GUI程序和SWT的最大的区别就是JFace的窗体类必须从ApplicationWindow继承 import orgeclipsejfacewindowApplicationWindow; public class FirstJFace extends ApplicationWindow { public static void main(String[] args) { … … } } 另外一个不同是在设置窗体上JFace通过ApplicationWindow类提供一系列的事件函数通过在这些函数中编写代码可以很方便地对窗体进行操作如可以在createContents函数中向窗体中加入控件 protected Control createContents(Composite parent) { // 这里边的代码就是上述的建立控件的代码只是要将shell换成parent } 由于使用JFace操作控件的方式和SWT类似本文将不再详细讨论感性趣的读者可以参考本文提供的源代码使用JFace的程序界面和SWT完全一样界面如图所示 图使用JFace实现的记事本程序界面 |