在QNX平台上开发Java应用程序

来源:百度文库 编辑:神马文学网 时间:2024/04/28 02:32:09
1.1 QNX 实时操作系统介绍
QNX 实时操作系统(QNX Real Time Operating System)是由位于加拿大渥太华的QNX软件系统公司开发的一个针对嵌入式应用的微内核操作系统。QNX软件系统公司成立于1981年,在过去的20多年中一直致力于微内核实时操作系统的研究与开发。目前的QNX 实时操作系统已经发展成一个可以使用在严实时应用中的高可靠性实时操作系统,能够运行在x86/Pentium, PowerPC, ARM, StrongARM, XScale, MIPS, SH-4等一系列硬件平台上,是在关键任务应用中首选的两个实时操作系统之一(另外一个是VxWorks)。
QNX 是一个与电气工程师协会(Institute of Electrical and Electronics Engineers,IEEE)发表的便携式操作系统界面标准(Portable Operating System Interface, POSIX) 相兼容的实时操作系统。该操作系统提供了一系列可裁剪的功能全面的高可靠性高性能组件,包括分布式计算,资源管理,网络应用,图形窗口系统,文件系统,以及对Java的支持等等。此外,QNX还是一个与Linux高度兼容的操作系统,由于gcc和gmake等Linux 平台上常用的应用程序开发工具已经被移植到QNX 平台上,很多为Linux平台编写的应用程序可以直接拿到QNX平台上编译运行。此外,QNX还提供了一个类似于Visual C++的应用程序集成开发环境,称为Photon Applicatioin Buider (PHAB)。在这个集成开发环境里程序开发人员能够很方便的开发和调试基于图形用户界面的QNX 应用程序。
更为重要的是,对于应用程序开发人员来说,QNX是一个完全免费的实时操作系统。根据QNX软件系统公司发布的使用授权协议,在一个产品商业化之前应用程序开发人员可以自由的使用QNX实时操作系统系统而无须向QNX 公司交付任何软件使用费用。同样,QNX的应用程序集成开发环境PHAB对于软件开发人员来说也是免费的。QNX 实时操作系统以及QNX应用程序集成开发环境均可以从QNX公司的主页www.qnx.com下载。
1.2 QNX 实时操作系统对Java语言的支持
QNX Neutrino使用IBM公司开发的业界领先的J9虚拟机为Java应用程序以及小应用程序提供了支持。目前可供选择的方案有两个,一个是与J2ME标准完全兼容的WebSphere嵌入式环境,另外一个是WebSphere客户环境,提供了一个可裁剪的Java 2语言标准的子集。由于QNX 是一个多任务操作系统,因此可以同时运行多个虚拟机为不同的应用程序提供服务。基于微内核的microGUI窗口界面系统为AWT提供了全面的支持,在其它平台上开发的基于AWT的图形用户界面可以不加修改的在QNX平台上运行。此外,QNX还通过使用本地线程保证了正确的线程调度。
IBM公司开发的J9虚拟机通过了Modena JT++以及Plum Hall JVS 等一系列严格的业界测试,是一个与J2ME标准完全兼容Java虚拟机。由于J9是一个专门为实时的嵌入是应用开发的虚拟机,因此在其设计中对速度优化,内存管理,线程管理,本地方法,垃圾回收,及时编译,可移植性以及可裁剪性能方面做了很大的努力。根据多个公开发表的测试结果,J9虚拟机是目前运行速度最快的嵌入式Java虚拟机。对本地方法的支持,使得应用程序开发人员能够直接控制外围设备,调用实时操作系统的功能。J9虚拟机本身对内存的要求极少,用户更可以通过一个配置工具使得应用程序在特定的嵌入式系统中对内存的要求降低到最小。就象一般的Java应用程序一样,内存的分配和回收都是通过虚拟机来自动管理的,因此在一般情况下不会产生内存泄露。此外,J9虚拟机还提供了一个垃圾回收机制管理工具,使得用户能够在运行时刻控制和改变所使用的垃圾回收机制。在线程管理方面,J9虚拟机直接使用底层实时操作系统所提供的线程调度机制,从而保证了正确的代码能够在正确的时间被执行。高度可裁剪的类库使得用户能够将应用程序所不需要的类和方法排除在嵌入式系统之外,从而进一步节省了对系统存储空间的要求,也间接地提高了嵌入式应用程序的执行速度。目前版本的J9虚拟机支持大多数流行的嵌入式软硬件平台,包括运行在x86, MIPS, PowerPC, SH-4, 68K, SPARC平台上的Windows, Linux, QNX, Solaris, AIX, Pocket PC, Palm OS等操作系统。由于J9虚拟机卓越不群的表现,它被Java Pro杂志评选为2002年度最佳嵌入式Java平台。同时,使用J9作为Java平台的WebSphere Studio Device Developer (也就是以前的Visual Age for Java Micro Edition) 也被Java Pro杂志评选为2002年度最佳嵌入式开发工具,又被Java World杂志评选为最佳Java设备应用程序开发工具。
值得一提的是,QNX 软件系统公司是Eclipse Consortium的发起者和最早的成员之一。Eclipse 是由IBM 公司牵头开发的开放源代码的Java应用程序开发平台,其目的是为应用程序开发人员提供一套完备的高度可裁剪的高性能软件开发组件。Eclipse Consortium成立于2001年11月,目前已经拥有Borland, IBM, QNX, Red Hat, SuSE, Sybase, Rational等18个成员。由Eclipse Consortium 发布的Java应用程序集成开发环境Eclipse是完全免费的,可以运行在Windows, Red Hat Linux, SuSE Linux, Solaris, QNX和AIX等操作系统上。也就是说,在QNX平台上也是可以使用集成开发环境Eclipse来开发Java应用程序的。
1.3 QNX 实时操作系统以及集成开发环境的安装和配置
QNX实时操作系统的安装非常简单。首先你需要从QNX公司的网站下载最新版本的QNX 操作系统,下载的地址是http://www.qnx.com/nc/download.qnx。目前最新的版本是QNX 6.2,下载文件是qnxnc620.iso,这是一个CD-ROM映像文件。将这个映象文件里面的内容刻录到一张光盘上,然后利用该光盘启动计算机即可开始安装QNX 操作系统。总的来说安装的过程相当的简单,只需要选择启动方式以及指定QNX 文件系统所在的位置即可。系统文件拷贝完成后将自动的重新启动机器,然后需要用root登录进入系统并且自动安装其它应用程序。在一台500 MHz + 128 MB的计算机上,安装过程通常都小于15分钟,相对来说还是非常快的。系统安装完成后,即可直接使用PHAB以及gcc等程序开发工具, 但是要使用Java还需要进行一点小小的配置。
J9虚拟机的缺省安装位置是/usr/eclipse/ive。在这个目录下有bin和lib两个子目录,bin目录包含了J9虚拟机的可执行文件和所需要的库文件,lib目录则包含了各种版本的Java类库。未来在QNX 系统上使用J9虚拟机,我们需要将合适的目录包括在PATH和LD_LIBRARY_PATH 这两个环境变量中。我们需要修改用户家目录(~)下面的.profile文件,使之包含如下语句:
export J9_HOME=/usr/eclipse/ive
export PATH=$PATH:$J9_HOME/bin:.
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$J9_HOME/bin
应用程序集成开发环境Eclipse SDK for QNX可以从Eclipse Consortium的主页下载,下载地址是http://www.eclipse.org/downloads/。将所下载的zip 文件拷贝到/usr目录中,然后使用unzip命令解压缩。然后你还需要下载针对 J9虚拟机的插件,下载地址是http://dev.eclipse.org/viewcvs/index.cgi/ %7Echeckout%7E/jdt-debug-home/plugins/org.eclipse.jdt.launching.j9/ index.html。你需要根据你所下载的Eclipse SDK for QNX的版本好选择一个合适的插件,然后将下载的zip文件解压缩到/usr/eclipse/plugins目录中。同样,我们需要修改用户家目录(~)下面的.profile文件从而将Eclipse 所需要的路径和库路径包含在环境变量PATH和LD_LIBRARY_PATH中。
export ECLIPSE_HOME=/usr/eclipse
export ECLIPSE_PLUGIN=/usr/eclipse/plugins/org.eclipse.swt/os/qnx/x86
export PATH=$PATH:$ECLIPSE_HOME
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ECLIPSE_PLUGIN
到此为止我们以及成功的安装与配置了QNX 实时操作系统以及相关的Java应用程序开发工具。下面我们简单的介绍几个常用的命令:
j9c -- 类似于Java SDK中的javac命令,是用来编译Java源代码的。
j9 -- 类似于Java SDK中的java命令,是用来运行Java应用程序的。
eclipse -- 这个命令启动Eclipse for QNX应用程序集成开发环境。
1.4 一个简单的Hello World程序
在没有开始写Hello World之前,我们首先介绍一下QNX 上的文本编辑器。很多熟悉类UNIX操作系统的朋友也许会对vi比较熟悉,但是从Windows操作系统过来的朋友也许不太喜欢。我们这里使用的是QNX 操作系统自带的图形化编辑软件ped。
利用下面命令启动ped:
#ped &
下面是HelloWorld.java的源代码:
public class HelloWorld { public static void main(String args[]) { System.out.println("Hello World!"); } }
使用j9c命令编译Java源代码:
#j9c HelloWorld.java
使用j9命令运行Java应用程序:
#j9 HelloWorld
需要注意的是,QNX 操作系统和Java语言都是大小写敏感的,所以一定要把大小写都写对了。另外,对源代码进行编译的时候需要加上文件扩展名,在运行一个Java应用程序的时候则不需要加上文件扩展名。如果排除了这几种错误之后你仍然无法正确的编译或者是运行你的Hello World程序,请参考 1.3正确配置你的PATH和LD_LIBRARY_PATH。
2.1 J9C 编译器的使用
j9c是J9虚拟机自带的字节码编译器,相当于标准版Java开发工具中的javac命令。这个编译器的用法如下:
#j9c <编译选项> <源代码文件 | 目录名>
在j9c编译器中主要的编译选项如下:
-help
打印于编译有关的帮助信息
-version
显示编译器的版本号
-classpath
指定编译时刻使用的类路径
-d
指定存放字节码文件的目录名,如果没有指定目标目录名,编译器将不生成包目录结构
-nowarn
隐藏编译器的警告信息
-warn
设定编译器的警告水平
-g
设定是否生成调试代码
2.2 J9虚拟机的使用
和标准版Java开发工具相类似,可以使用j9命令启动J9虚拟机。这个命令的用法如下:
#j9 <运行选项> 主类名称 [运行参数]
#j9 <运行选项> -jxe:jxe文件 [运行参数]
J9虚拟机中主要的运行选项如下:
-jxe
运行所指定的jxe文件
-jxespace
为jxe文件指定所使用的内存(十六进制)
-jxeaddr
从内存中直接运行一个jxe格式的应用程序
-cp
将path指定为运行时刻所使用的类路径
-D
在运行之前设定系统的环境变量
-debug
在指定的端口启动JDWP调试服务器
-jcl
指定所使用的JCL动态连接库
-verbose
详细输出相关的调试信息其中class和gc是缺省的选项
2.3 J9虚拟机上的标准类库
嵌入式应用程序和普通应用程序的最大的区别在于嵌入式应用程序处处要受到目标平台的处理速度,内存大小以及存储空间的限制,而基于PC 的应用程序所受的限制则相对要小很多。基于以上考虑,所选择的虚拟机必须在能够满足系统要求的情况下尽可能的少占用系统存储空间,经过编译的字节码文件必须尽可能的以提高执行效率。因此,在嵌入是应用程序的开发中,虚拟机的裁剪是提高系统整体性能的至关重要的一个环节。
基于如上需求,J9虚拟机专门为不同的应用提供了不同的标准类库。这些标准类库均提供了运行Java应用程序所必须的基本类,例如Java语言中最基本的java.lang.Object和java.lang.String等等。一个完全版的 J9虚拟机通常包括如下标准类库:
jclXtr
这是一个极小型的类库,大约90 KB, 当你的存储空间和内存极度紧张并且你能够容忍功能局限的情况下可以考虑这一个类库(QNX 的缺省安装里面没有)。这个类库提供了如下Java 2标准类库的一个子集:java.io, java.lang, java.net, java.util。
jclCldc
这是J9虚拟机向资源极度紧张的目标平台所推荐的最小配置,大约166 KB。在jclXtr类库中仅提供了最基本的 IO功能,在jclCldc 类库中则大幅度的增加了对IO以及网络应用的支持,例如http, ftp, comm, datagram, file, serversocket, socket等。这个基本类库所在的位置是$J9_HOME/lib/jclCldc
jclCore
这是一个为微小型设备设计的一个轻量级的基本类库,它提供了基本的文件IO以及对网络应用的支持,大约占用空间346 KB,是J9虚拟机为资源不太紧张的目标平台所推荐使用的核心类库(所以叫做jclCore )。这个类库包括了Java 2中如下包里面的大部:java.io, java.lang, java.net, java.util, java.util.zip。在QNX 的缺省安装中不包括jclCore基本类库。
jclGateway
这个基本类库是在jclCore基本类库的基础上构建的,大约600 KB,主要的改进是提供了安全检查的功能。这个类库除了jclCore 基本类库所包含的内容之外还提供了如下包和类:完整的java.lang.reflect包; java.net.URL包,但是不包括URLClassLoader包; java.lang.SecurityManager包,但是不包括java.security.acl包;提供java.lang.Runtime.exec()方法。在QNX 的缺省安装中不包括jclGate基本类库。
jclMax
这是一个专门为资源比较宽裕的目标平台所设计的基本类库,大约2732 KB。这个基本类库里面包括了Java 2 里面的大多数包和类,包括java.lang, java.lang.ref, java.lang.reflect, java.io, java.net, java.math, java.txt, java.util, java.util.jar, java.util.zip。此外,jclMax基本类库还基于如下包提供了Java 2风格的安全检查功能,包括: java.security, java.security.interfaces, java.security.acl, java.security.spec, java.security.cert, com.ibm.oti.security.provider。这个基本类库所在的位置是$J9_HOME/lib/jclMax
jclPersonal
这个类库提供了AWT, RMI以及对Java Bean的支持。QNX 的缺省安装中不安装这个类库,但是可以从IBM 的主页上面下载。另外,如果你已经在QNX上面安装了Eclipse的话,你也可以使用SWT来构建你的图形界面。这些内容将会在本系列文章的后面讲述。
不包括在QNX 缺省安装中的J9标准类库可以从IBM 公司开发的Webshpere Studio Device Developer 中获得。Webshpere Studio Device Developer是基于Eclipse项目的针对嵌入式 Java应用的一个集成开发环境,可以从IBM 公司的主页免费下载,下载地址是 http://www.ibm.com/software/ad/embedded。
2.4 一个从串口设备采集数据的简单程序
数据采集与处理是当前嵌入式应用的一个热点。在这种应用中,嵌入式系统与各种各样各样的传感器或者是数据采集器等外接设备进行通讯,在其内部对各种数据进行处理并向外接设备输出反馈信号。到目前为止,串口通讯(主要是RS-232和RS-485)仍然是传感器与主机进行通讯的主流方式,因此在一个嵌入式应用程序中,经常需要通过串口与串口设备进行通讯。
在标准版的Java语言中,串口通讯是通过扩展类库javax.comm来实现的。由于这个扩展类库在标准的JDK 中并不提供,需要使用到串口通讯功能的软件开发人员必须到IBM或者是Sun公司的网站去下载,在一定程度上影响了这个扩展类库的普及和使用。J9虚拟机在设计上充分考虑到了嵌入式应用的需求,在各个版本的标准类库中都提供了对串口通讯的支持。这些功能被放在serial.jar这个包里面,可以在如下目录下找到:
$J9_HOME/lib/jclCdc/serial.jar
$J9_HOME/lib/jclFoundation/serial.jar
在QNX 系统上,J9虚拟机缺省的类路径(CLASSPATH)是jclMax标准类库,也就是$J9_HOME/lib/jclMax/classes.zip。也就是说,如果在程序中需要用到串口通讯的时候,我们需要将serial.jar添加到虚拟机的类路径里面去。在QNX系统上设置类路径的方法于Linux系统比较相似,只需要修改 .profile文件把新的CLASSPATH定义好就可以了。
# export CLASSPATH=$J9_HOME/lib/jclCdc/serial.jar
J9虚拟机缺省的类路径,也就是$J9_HOME/lib/jclMax/classes.zip 不需要显式的定义。
serial.jar里面包含了很多用于与串口设备进行通讯的类,需要详细了解的网友可以自行参考相关的文档。一般来说,于串口设备进行通讯需要经过如下步骤:
(1) 创建一个SerialConfiguration对象,然后根据特定设备的通讯参数修改一下波特率等值。
(2) 创建一个SerialPort对象,在创建这个对象的时候需要使用到串口的名称以及刚才创建好的SerialConfiguration。
(3) 利用SerialPort类的getInputStream() 和getOutputStream()方法获得串口设备的输入输出流,通过该设备的输入输出流即可与该设备进行通讯。
(4) 当不再使用这个串口设备的时候,利用SerialPort.close()关闭与该设备的连接,同时释放所占用的系统资源。
在QNX 系统下,设备名被保存在/dev目录下,串口设备被起名为ser(n),其中n是该串口设备的编号,从1 开始计数。例如/dev/ser1相当于晕倒死系统上的COM1,/dev/ser2相当于晕倒死系统上的COM2。因此,虽然J9 虚拟机在各个平台上都提供了对串口进行操作的包serial.jar,但是程序员仍然需要考虑到在不同的平台上设备名是不一样的。
下面的示范程序演示了与串口进行通讯的一般过程。该程序与连接在ser1 的设备进行通讯,将该设备的输出信息打印到屏幕上。
import java.io.*; import com.ibm.ive.serial.*; public class SerialDemo { public static void main(String[] args) { // 构造SerialPortConfiguration对象并且配置通讯参数 SerialPortConfiguration SPC = new SerialPortConfiguration(); SPC.baudRate = 19200; SPC.dataBits = 8; SPC.stopBits = 1; SPC.parity = 0; try { // 构造SerialPort对象,构造成功以后系统已经与指定的设 // 备连接上了 SerialPort SP = new SerialPort("/dev/ser1", SPC); // 获得设备的输出并读取数据 InputStream DevIn = SP.getInputStream(); for (int i = 0; i < 10000; i++) System.out.println(DevIn.read()); // 关闭与串口设备的连接 SP.close(); } catch (Exception e) { System.out.println(e.getMessage()); } } }
对上面这个示范程序进行编译的时候,由于程序中使用了jclMax标准类库之外的类,所以需要在编译的时候指定类路径,也就是:
# j9c -classpath $CLASSPATH SerialDemo.java
在运行这个示范程序的时候,不需要再次显式的指定类路径,因为j9命令会自己到系统的CLASSPATH里面去找:
# j9 SerialDemo
需要说明的是,在J9虚拟机中同样提供了对扩展类库javax.comm的支持。但是基于 J9虚拟机的嵌入式Java应用中,普遍的做法是直接使用J9虚拟机本身的serial.jar。
3.1 AWT类库的安装和配置
对嵌入式Java比较熟悉的朋友一定知道目前大多数的嵌入式虚拟机都提供了对AWT 的支持。例如Sun公司开发的Personal Java,Insignia公司开发的Jeode,Nsicom公司开发的CrEme,还有PERC公司开发的Perc,当然还包括我们正在介绍的IBM J9。就我个人所了解的情况,Nsicom公司开发的CrEme 是目前唯一的一个支持Swing 的嵌入式Java虚拟机。关于为什么在嵌入式Java中普遍使用AWT而不使用Swing的问题,我们会在这一章的第三节进行讨论。
根据我们在2.3 节中的介绍,J9虚拟机在jclPersonal 标准类库中提供了对AWT的支持,但是在QNX的缺省安装中并不包括这个类库。因此,我们需要从J9虚拟机的新家WebSphere Studio Device Developer (也就是原先叫做Visual Age for Java Micro Edition的)中获得这个类库。
首先我们必须从IBM 的网站下载WebSphere Studio Device Developer,下载的地址是www.ibm.com/software/ad/embedded/。这是IBM公司基于 Eclipse开发的嵌入式Java集成开发环境,如果你以前用过Visual Age for Java或者是Eclipse的其它版本的话,想来应该很容易的就能够上手。WSDD有两个版本,一个是给Windows平台的,另外一个是给Linux平台的。但是在这个标准版的WSDD中既不包括QNX平台的运行环境,也不包括我们所需要的jclPersonal 类库,所以我们还要下载WSDD的Software Updates。QNX 平台的运行环境在Runtime Software Updates中,jclPersonal库在Custom Environment Software Updates中,所以这两个update我们都要下载。
首先安装WSDD,将下载来的Software Updates解压到一个临时目录下,然后启动WSDD。从主菜单选取Help -> Device Developer Updates。点击Add或者是Update All,在随后跳出来的对话框里面选Local Predefined Locations。在最下面的Location一栏里面填上你所需要安装的Update,格式为file:/$dir,例如:
file:/c:/temp/wsddupdates/wsdd/4.0/runtimes/
file:/c:/temp/wsddupdates/wsdd/4.0/wce/
安装结束以后在下面这个目录找到QNX 的jclPersonal类库prsnlqnx.jar:
wsdd/wsdd4.0/ive/runtimes/qnx/common/ive/lib/jclMax/
如果你的QNX 和Windows或者是Linux主机是两台独立的计算机的话,你可以通过网络或者是其它的可移动存储设备将prsnlqnx.jar拷贝到你的 QNX 系统上。如果你的QNX 和晕倒死或者是利怒死主机是安装的同一台计算机的不同硬盘或者是同一块硬盘的不同分区上的话,你可以启动QNX 进入文件管理器,然后进入/fs目录看看里面是不是能够看见其它的硬盘或者是分区。如果没有看到你所需要的硬盘或者是分区,你可以使用mount命令启用相对应的硬盘或者是分区,使得你可以从QNX 系统下对这些硬盘或者是分区上面的文件进行操作。
将prsnlqnx.jar文件放到/usr/eclipse/ive/lib目录下,然后修改类路径,最好是在~/.profile文件里面改:
export CLASSPATH=$CLASSPATH:/usr/eclipse/ive/lib/prsnlqnx.jar
到目前为止,我们已经完成了AWT类库的安装和配置。
3.2 一个简单的AWT图形用户界面
AWT是Java语言中构建图形用户界面的标准。由于Java语言卓越的跨平台特性,在一个平台上编写的基于AWT的图形用户界面可以不加修改的直接移植到另外一个平台上使用。通常来说,构建一个基于AWT的图形用户界面需要经过如下步骤:
(1) 创建一个顶级容器对象,例如Window或者是Frame。
(2) 在顶级容器对象上面创建用户所需要的控件。
(3) 初始化所有的控件,包括大小和初始值等,为控件的事件注册必要的监听器Listener。
(4) 打开主窗口。
下面是一个简单的基于AWT的图形用户界面:
import java.awt.*; import java.awt.event.*; public class HelloAwt extends Frame { public HelloAwt() { Label label = new Label("Hello AWT!"); add(Label); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } } } public static void main(String[] args) { HelloAwt hello = new HelloAwt(); hello.setTitle("I Love Java!"); hello.pack(); hello.setVisible(true); } }
使用下面的命令编译以上例程:
#j9c -classpath $CLASSPATH HelloAwt.java
使用下面的命令运行以上例程:
#j9 HelloAwt
在Sun 公司撰写的Java入门教程The Java Tutorial中有专门的一章介绍了基于AWT 的图形用户界面。但是由于目前Swing已经正式成为标准版Java2 中构建图形用户界面的标准,这一章的内容被Sun 公司从The Java Tutorial网站上撤下,但是各位读者仍然可以从Sun 公司的网站下载这部分的教程:
http://java.sun.com/docs/books/tutorial/information/download.html#OLDui
3.3 关于AWT和Swing的一点讨论
在第一节中我们提到了目前大多数的嵌入式Java虚拟机都提供了对AWT 的支持但是不提供对Swing 的支持。但是,在标准版的Java平台上Swing 才是推荐使用的图形界面系统,在Sun 公司所提供的Java Tutorial 中甚至把基于AWT 的图形用户界面设计这一部份从其网站中删除,需要利用到AWT 进行图形用户界面设计的用户只有将该部份下载到本地硬盘才能够使用这部份教程。在标准版Java中正值春风得意的Swing 为什么到了嵌入式应用中便不再吃香了呢?
AWT 是Abstract Window ToolKit (抽象窗口工具包)的缩写,这个工具包提供了一套与本地图形界面进行交互的接口。AWT 中的图形函数与操作系统所提供的图形函数之间有着一一对应的关系,我们把它称为peers。 也就是说,当我们利用 AWT 来构件图形用户界面的时候,我们实际上是在利用操作系统所提供的图形库。由于不同操作系统的图形库所提供的功能是不一样的,在一个平台上存在的功能在另外一个平台上则可能不存在。为了实现Java语言所宣称的"一次编译,到处运行"的概念,AWT 不得不通过牺牲功能来实现其平台无关性,也就是说,AWT 所提供的图形功能是各种通用型操作系统所提供的图形功能的交集。由于AWT 是依靠本地方法来实现其功能的,我们通常把AWT控件称为重量级控件。
Swing是在AWT的基础上构建的一套新的图形界面系统,它提供了AWT 所能够提供的所有功能,并且用纯粹的Java代码对AWT 的功能进行了大幅度的扩充。例如说并不是所有的操作系统都提供了对树形控件的支持, Swing 利用了AWT 中所提供的基本作图方法对树形控件进行模拟。由于 Swing 控件是用100%的Java代码来实现的,因此在一个平台上设计的树形控件可以在其他平台上使用。由于在Swing 中没有使用本地方法来实现图形功能,我们通常把Swing控件称为轻量级控件。
说到这里我想各位读者应该明白了AWT和Swing之间的基本区别:AWT 是基于本地方法的C/C++程序,其运行速度比较快;Swing是基于AWT 的Java程序,其运行速度比较慢。对于一个嵌入式应用来说,目标平台的硬件资源往往非常有限,而应用程序的运行速度又是项目中至关重要的因素。在这种矛盾的情况下,简单而高效的AWT 当然成了嵌入式Java的第一选择。而在普通的基于PC或者是工作站的标准Java应用中,硬件资源对应用程序所造成的限制往往不是项目中的关键因素,所以在标准版的Java中则提倡使用Swing, 也就是通过牺牲速度来实现应用程序的功能。
4.1 SWT类库的安装和配置
Eclipse 项目的发布在IT界可以说是一次震撼,这不仅仅是因为IBM 公司无偿公开了花费4000万美元开发出来的一整套代码,也不仅仅是因为支持这个项目的包括目前在市场上相当吃香的Rational, Borland, Red Hat以及QNX等公司。最让人吃惊的是:Eclipse 项目的矛头直接针对的是IBM公司最亲密无间的Java合作夥伴 -- Sun公司。就象Eclipse这个名字所意味的那样,IBM 的目的是要建立一套各种程序设计语言都能够使用的模块化的开发平台,并且希望它能够成为一个业界公认的标准平台。
Eclipse项目中最令人震撼的一点是它用称为SWT的的图形库和工具包取代了Java标准中的AWT和Swing。根据Eclipse项目的解释,SWT直接调用了操作系统的图形库,从而使得Java应用程序的Look & Feel 与操作系统的习惯完全一致;更为重要的是,对本地方法的直接调用大幅度的提高了基于SWT 的Java应用程序的运行速度。关于SWT与AWT/Swing的优点和缺点我们将在这一章的第三节中进行比较和讨论。
为了在我们的Java应用程序中使用SWT,我们需要做一点必要的配置,如下:
(1) /usr/eclipse/plugins/org.eclipse.core.runtime/runtime.jar 是Eclipse平台的运行库,需要将它放到类路径里面。
(2) /usr/eclipse/plugins/org.eclipse.ui/workbench.jar是Eclipse 平台的图形界面库,需要把它放到类路径里面。
(3) /usr/eclipse/plugins/org.eclipse.swt/ws/photon/swt.jar里面是SWT 的基本类库,需要将它放在类路径里面。
(4) /usr/eclipse/plugins/org.eclipse.swt/os/qnx/x86 这个目录下面存放的是SWT 与本地方法的接口,需要放在LD_LIBRARY_PATH里面。
修改.profile文件,如下:
export CLASSPATH=$CLASSPATH:/usr/eclipse/plugins/org.eclipse.core.runtime/runtime.jar
export CLASSPATH=$CLASSPATH:/usr/eclipse/plugins/org.eclipse.ui/workbench.jar
export CLASSPATH=$CLASSPATH:/usr/eclipse/plugins/org.eclipse.swt/ws/photon/swt.jar
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/eclipse/plugins/org.eclipse.swt/os/qnx/x86
改动过这些设置以后,最简单的办法是重新启动Photon来让这些新的设置生效。
4.2 一个简单的SWT图形用户界面
通常来说,构建一个基于SWT 的图形用户界面需要经过如下步骤:
(1) 创建一个Display对象,该对象代表一个SWT 进程(session)。
(2) 创建一个或者是多个Shell对象,一个Shell对象相当于我们在AWT/Sing里面所说的顶极容器,也就是应用程序的主窗口。
(3) 在Shell对象上面创建用户所需要的控件。
(4) 初始化所有的控件,包括大小和初始值等,为控件的事件注册必要的监听器Listener。
(5) 打开主窗口。
(6) 启动事件处理循环,一直到用户结束程序的运行。
(7) 垃圾回收。
下面是一个简单的基于SWT 的Java应用程序HelloSwt:
import org.eclipse.swt.widgets.*; import org.eclipse.swt.SWT; public class HelloSwt { public static void main(String[] args) { Display display = new Display(); Shell shell = new Shell(display); Label label = new Label(shell, SWT.CENTER); label.setText("Hello SWT!"); label.setBounds(shell.getClientArea()); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose(); } }
使用下面的命令编译以上例程:
#j9c -classpath $CLASSPATH HelloSwt.java
使用下面的命令运行以上例程:
#j9 HelloSwt
我们可以看到,基于SWT的图形用户界面在外观上和基于AWT的图形用户界面有明显的不同。更为重要的是,能够明显的感受到HelloSwt的启动速度比HelloAwt要快很多。 QNX 高效的微内核图形界面系统当然是提高用户应用程序运行速度的一个方面,但是更重要的是SWT 直接调用了QNX 的微内核图形界面系统的功能,而AWT 则没有利用到操作系统所提供的这些优势。
SWT 是一套与AWT/Swing 完全不同的图形界面系统,新接触SWT 的程序员还是需要花费一段时间来熟悉SWT的结构和API。下面推荐的几个参考资料能够让你轻松的开始利用SWT 进行图形用户界面设计:
The Programmer's Guide for Eclipse, 这是Eclipse项目发布的官方程序员手册,其PDF 版可以从这个地址下载:
http://www.eclipse.org/documentation/pdf/org.eclipse.platform.doc.isv.pdf
这份文档也可以从这个网站联机查看:
http://download.eclipse.org/downloads/documentation/2.0/html/plugins/org.eclipse.platform.doc.isv/
另外,www.eclipse.org最近在其网站上发布了关于SWT的结构及其应用的一系列文章,也非常的有参考价值。如果有感兴趣的网友,请自行到 Eclipse 的网站查看。
4.3 关于SWT和AWT/Swing的一点讨论
通过3.3 的讨论我们知道在AWT 中的图形用户界面是通过本地方法来实现的,每个AWT 方法都有一个与其对应的本地方法,称为peer。由于平台无关性的需要,AWT 所能够实现的功能是各种不同操作系统的图形库所提供的功能的交集。通过这种机制,在所有的平台上相同的AWT 控件的Java代码是一样的,其性能也是类似的。SWT 所采取的则是一种完全相反的方法,它是通过一些本地方法将操作系统的图形库完全的暴露给虚拟机。在这些本地方法的基础上,SWT 通过纯粹的Java代码实现了需要的图形界面功能。由于各个操作系统所提供的图形库是不一样的,同样一个控件在不同平台上的Java实现通常来说是不一样的。基于同样的道理,同样的SWT 程序在不同平台上的性能和表现也许是不一样的。
SWT 所采取的这种方法决定了它在技术上要比AWT 要具有更多的优点,如下:
(1) 如果操作系统A 支持某种图形控件而操作系统B 不支持,AWT 就会出于平台无关性的要求拒绝提供这个控件。SWT 则会在操作系统A 上原封不动的调用操作系统所提供的控件,在操作系统B 上则使用该操作系统所提供的其它功能对该控件进行模拟。例如Windows平台本身就提供了树和表格等控件而其它一些操作系统不提供这些控件,SWT 在Widnows平台上就会直接调用Windows的方法来实现这些控件,AWT 为了实现平台无关性拒绝提供这些控件,Swing 则为了实现纯Java的目的在AWT 的基础上自己来画这些控件 -- 尽管它画出来的东西很少有画得好的。
(2) 由于SWT 大量的采用了本地平台所提供的图形库,SWT 中的控件风格跟本地平台的UI风格是完全一致的,因为在SWT 中的控件基本上就是操作系统本身的控件。这一点对于AWT 来说是比较相似的,但是Swing 的表现就不太一样了,譬如说在Windows XP上面用Swing 画一颗树它看起来就跟Widnows 2000上面的树一模一样,尽管Windows XP跟Widnows 2000本身的树形控件是不一样的。
(3) 在SWT中,大部份的事物逻辑都是用Java写的,在SWT 中C/C++代码的比重远比AWT中C/C++代码比重要小。这样使得程序设计人员能够更加方便的对SWT 应用程序进行调试,也能够更清楚的知道在后台运行的本地方法究竟在做什么事情。更为重要的是,SWT利用比AWT 更少的C/C++ 代码实现了比AWT 更快的图形用户界面,这个优势在嵌入式应用中往往是决定性的。
SWT 的缺点主要在于两点:(1) 不是Java语言标准;和(2) 支持的平台太少。目前版本的Eclipse仅仅支持Windows 98/ME/2000/XP, RH 7.1, SuSE 7.l, Solaris 8, QNX, AIX和HP-UX几个有限的平台。而作为Java 语言标准的AWT/Swing 则在目前大部份的主流和非主流操作系统上都有支持。