Java中AWT、Swing与SWT三⼤GUI技术的原理与效率差异看了⼀下对Java 讨论的帖⼦,所以写了⼀篇⽂章来阐述⼀下各种GUI技术的优劣。
Java世界中,⽬前最知名的三⼤GUI库分别是:
1、AWT( Window Toolkit)抽象窗⼝⼯具包库,包含于所有的Java SDK中
2、⾼级图形库,包含于Java2 SDK中
3、来⾃IBM 开源项⽬的SWT(Standard Widget Toolkit)标准窗⼝部件库,不包含于JDK中,需要从Eclipse单独下载
⼀、AWT的原理:⼩巧却简陋的GUI系统 AWT出现于Java 1.x中,是Java初期所内置的⼀种⾯向窗⼝应⽤的库。AWT使⽤的技术是对等设计模式(即Peer),其结构关系参见下图。 从这幅类关系图很容易看出AWT的技术实现和Peer设计模式。图中,黄⾊的类是java.awt包中的类,浅灰⾊部分是Java虚拟机部分,⽽深灰⾊则是Windows平台。 awt的重点是对等Peer设计模式。所谓Peer对等设计模式就是将awt控件直接对应到运⾏平台上的⼀个类似或者等同控件上。⽐如图中的Button类就是对应了深灰⾊的Windows的标准Button功能。 对等模式⽤于在两个控件间之间建⽴⼀个相互作⽤的联系,⽽充当纽带的则是Java虚拟机和虚拟机-GDI的接⼝(以Windows为例⼦)。所以,我们可以看出,awt⾸先需要经过
javaswing和javafx通⽤的Java技术来控制图形、事件等,然后Java虚拟机再将请求传送到具体的平台图形和控件接⼝去交互。 对等模式的效率并不很⾼,因为AWT通过了虚拟机和虚拟机-GDI这两个层次来完成⼀个操作,经过的层次系统越多,速度和效率就越慢。⽽且Peer对等模式有⼀个致命的弱点:移植性⾮常差! 这就是Sun为什么要⽤Swing来诱惑我们离开AWT的主要原因。因为既然是对等模式,那么AWT就必须使⽤所有图形操作系统的图形接⼝功能的交集,因为 AWT的接⼝只有⼀套,所以,为了保证移植性,就只能使⽤所有系统都能够⽀持的最少特性。因⽽我们经常可以听见有⼈抱怨AWT的功能太少,图形太难看等等,这是为了保证移植性⽽作出的牺牲。⼆、猛犸巨兽的诞⽣-Swing 从Java2 即Java 1.2版本开始,Sun开始在JDK中提供⼀套新的图形界⾯接⼝系统-Swing。所有Java爱好者都投⼊了对Swing的研究和迷恋。随着⼀⼤批使⽤Swing作为界⾯技术的IDE和程序出现,很快⼤家都意识到Swing的问题所在。 ⼀些⼈认为Swing是轻量级的GUI系统,⽆论官⽅如何说,没有⼀个Java程序员会认为Swing是轻量级的,相反,Swing是⼀个⾮常巨⼤的GUI库,这⼀点已经是Java界的共识。 Swing的⼀些底层类是借⽤了AWT的Component、Container、Window等少数⼏个基础类。估计的原因是为了保持与AWT的兼容,⽅便⼤家将代码移植到Swing上。 下⾯是Swing的类关系图: 菊黄⾊类为Swing包的类。对⽐⼀下Swing的图与AWT的图,我们可以发现,Swing图中,awt体系中的深灰⾊Windows控件类已经被去掉了。因为Swing不再沿⽤Peer对等模式来实现GUI界⾯。 这是Swing的核⼼思想之⼀,Swing是完全基于Java⾃绘制图形⽽实现的,因⽽Swing的界⾯看起来与Windows不再有任何类似,尤其是窗⼝控件的样式(虽然我们也可以通过换肤来达到模拟Windows界⾯的效果)。所以
上图清楚的表明了Swing是⼀个⾼层的GUI系统,⽽不像AWT那样与运⾏平台技术更加靠近的系统。我们仍然⽤Button与Panel来做了⼀个例⼦,图中关系看出,Swing 的类继承关系⽐AWT要复杂的多,⽽且Swing类⼤多都经过了中间的转接类-JComponent。⽽我们常⽤的JFrame则另辟蹊径,从awt的window继承了下来。 这种结构关系决定了Swing的庞⼤与复杂性。很多初学者都难以理解Swing的模式和结构。 Swing 中的控件都是利⽤Java图形功能绘制出来的,⽽不是对应到平台的⼀个具体控件实现。我们所⽤的所有Swing控件都是直接或者间接⽤Graphics绘制出来的,这种实现⽅式最⼤的好处是很灵活,我们想要什么样的控件,就直接⽤Graphics绘制出来就是了。 Sun之所以⽤这种⽅式来实现,是为了在不牺牲移植性的基础上加⼊丰富的界⾯交互功能。但是缺点也很明显:Swing的速度和效率是所有GUI系统中最慢的。 JBuilder和NetBeans的IDE都是纯正的Swing界⾯,启动⼀下,然后操作⼀下,⽐如拖动窗⼝之类的试试,你就会明⽩我在说什么。 之所以导致这个结果,其原因是: 1、Swing的类层次太深,⼀个JFrame经过了4层的类继承关系,如果再加上虚拟机的图形功能内部实现,就有6层的转接关系,每⼀次的继承和转接都会消耗系统资源和速度损失。(过多的继承会降低系统的速度,因为操作⼦类往往是使⽤基类指向来完成通⽤操作的) 2、Swing是基于⾃绘制图形技术的,⽽Java为了保持可移植性,所以⽆法使⽤硬件加速和平台特性来加快图形操作的速度。因⽽Java的图形技术都是“⾼层”的图形技术,就好像我们⽤Windows GDI去做动画⼀样,当然速度会很慢。三、新的曙光-SWT 应该说,稍有阅历的Java的程序员都知道很多⼈对Swing效率低下的抱怨。IBM赞助的Eclipse开放源码项⽬,搞了⼀个另类的GUI系统-SWT。 SWT是⼀个⾮常独特的技术,其核⼼思想
和Windows上的DirectX如出⼀辙,也许SWT的程序员真的是借鉴了DirectX成功的秘诀。 下⾯是SWT技术原理的类关系图:
我们会看见,SWT的类关系⾮常直接⽽且易懂,有点像Delphi的API接⼝思想(此是我随便乱弹,与Delphi没有什么关系)。最重要的⼀点就是SWT的核⼼思想:SWT的功能实现是完全构筑在以JNI为基础的,对运⾏平台的直接调⽤封装上的。
我们可以从图中看见,SWT的功能没有通过任何Java虚拟机来操作,⽽是直接调⽤Windows GDI和Shell功能,这⼀点是通过JNI⽅法调⽤完成。
⼀定会有⼈说SWT破坏了java的移植思想,不过Eclipse的⼤范围流⾏,正好证明了SWT⾮但没有阻碍移植性,反⽽提⾼了各种操作系统对于Java GUI的利⽤和期待。这不能不说Eclipse项⽬组是充满智慧的。
在Eclipse下,plugin⽬录的swt⽬录下,你可以发现⼀个dll动态库⽂件,这个dll就是JNI⽅法调⽤库。
基于SWT技术实现的Eclipse界⾯不但速度很快,效率很⾼,⽽且⽐Swing要美观的多。这就是直接调⽤封装的效果。
我们看看SWT的源代码就能更加明⽩为什么SWT那么流⾏,为什么SWT的速度像飞⼀样快,下⾯是从button类中抽取的⼀⼩段代码:代码:
int callWindowProc (int msg, int wParam, int lParam) {
if (handle == 0) return 0;
return OS.CallWindowProc (ButtonProc, handle, msg wParam, lParam);
}
int windowProc () {
return ButtonProc;
}
LRESULT wmDrawChild (int wParam, int lParam) {
if ((style & SWT.ARROW) == 0) return super.wmDrawChild (wParam, lParam);
DRAWITEMSTRUCT struct = new DRAWITEMSTRUCT ();
OS.MoveMemory (struct, lParam, DRAWITEMSTRUCT.sizeof);
int uState = OS.DFCS_SCROLLLEFT;
switch (style & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT)) {
case SWT.UP: uState = OS.DFCS_SCROLLUP; break;
case SWT.DOWN: uState = OS.DFCS_SCROLLDOWN; break;
case SWT.LEFT: uState = OS.DFCS_SCROLLLEFT; break;
case SWT.RIGHT: uState = OS.DFCS_SCROLLRIGHT; break;
}
if (!getEnabled ()) uState |= OS.DFCS_INACTIVE;
if ((style & SWT.FLAT) == SWT.FLAT) uState |= OS.DFCS_FLAT;
if ((struct.itemState & OS.ODS_SELECTED) != 0) uState |= OS.DFCS_PUSHED;
RECT rect = new RECT ();
OS.SetRect (rect, struct.left, p, struct.right, struct.bottom);
OS.DrawFrameControl (struct.hDC, rect, OS.DFC_SCROLL, uState);
return null;
}
我想任何⼀个有点Windows编程知识的⼈都会惊讶SWT的⽅式和做法,LRESULT、WindowProc都是
做什么的,我想不⽤我多说了。我第⼀次看见SWT的代码时,惊讶的张⼤了嘴,我实在⽆法想象SWT项⽬组敢于将Java技术与Windows平台结合到如此紧密(当然,Linux 平台版本也同样的结合紧密)。我居然在SWT⾥发现了⼀个叫Tray的类,猜猜看它是⼲什么的?Tray可以让你在java程序中显⽰⼀个任务栏图标,极度晕眩!
我想,不⽤再继续介绍SWT了,你⼀定也很兴奋,从SWT开始,JavaGUI并不⼀定意味着缓慢、低效率、弱⼩的功能,Windows程序的眩⽬与速度,Java程序也可以拥有,这就是SWT的价值。
更加重要的是,SWT打破了长久以来⼈们对于移植性的误区,似乎移植性就只能使⽤少到可怜的功能,我们也可以⽤JNI来拥抱Java的世界,我想,将来不仅仅是界⾯会借助JNI的⽅式,也许我们的很多Java思想都会悄悄的发⽣改变,也许有⼀天我们的Java代码可以运⾏的像VB⼀样快,这种思想意识的变⾰就是SWT的价值。
⾄于Swing的结局,我不知道,但是我知道我更加喜欢轻量级的⽽且快速的SWT,给你的程序多⼀个选择吧。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论