如何编写高效swing程序

来源:互联网 发布:c语言调试器 编辑:程序博客网 时间:2024/06/06 09:54

每每讨论哪种程序开发语言更有前途时,总是引来吵骂一片,或有人居高临下,认为程序设计思想才是精华,只有菜鸟才会去讨论语言的优劣。然而,语言之间的差异无法回避,不同的语言侧重点不同,善于解决的问题也不同。我以C++开始学习编程,但自从接触java之后,深被java之美所吸引,C++、C#之类早已不是我要解决问题时会考虑使用的语言,除非因为合作问题而迁就。因此,我是一个java程序员,我喜欢java,喜欢java的纯粹和简单,还有其背后强大的社区,而java无疑是一门综合能力非常强的语言。

java一般用于后端服务,很少用来做界面编程,但千万不要认为java不善于界面编程,因为我们仍然可以使用java来制作出超乎想象的界面程序。然而,相比于MFC或者C#使用VS在工具箱中拖拖拽拽各种控件来构建界面,你需要学习更多,尽管eclipse和netbeans已经分别对swt和swing界面构建的简化做出了一些类似VS工具箱的努力。

说到java界面编程,那就不得不提awt、swing、swt。

awt概述:

awt是sun提供的最原始的java gui工具包,使用本地gui控件来构建用户界面,或许是出于对java跨平台性支持的考虑,它遵守最小公分母原则,仅提供了所有java环境提供者所共有的本地gui控件以及控件特性,无法满足使用需求。从用户需求出发,awt无疑是一个糟糕、失败的作品,事实上,awt是如此的“古老”,现在应该不会有人会考虑使用它了,awt如今不过是作为兼容性维持者和swing支持者的存在。

swing概述:

swing基于awt、为了解决awt的缺陷而构建。为了java的跨平台性、同时能够为用户提供足够使用的控件,swing走了一条相对极端的道路。swing遵守最大公分母原则,为用户提供各个平台所能提供的几乎全部控件,同时将对本地控件的依赖性降低到了极致,除了窗体等顶层控件,swing中绝大部分控件(JComponent)都是纯java实现,这也确保了swing构建的用户界面在各个平台上具有无可比拟的一致性。同awt一样,swing也是sun提供的JDK的标配。

有人认为swing界面有些奇怪,和本地其他程序的界面风格格格不入,那正是由于swing不依赖本地控件,纯java模拟控件的缘故。当然,swing也提供了一些lookandfeel方式,让swing界面看起来像本地界面。但我觉得这么做完全没有必要:做应用软件,界面简单快捷就好,像不像本地界面无关紧要;做娱乐软件,本地界面样式我还觉得不够丰富多彩,同样需要修饰。

swt概述:

这是一个有趣的事情,swing的存在已经完全满足使用要求,swing也已经足够优秀了,至少我是这么认为的,但仍然有“好事者”IBM搞了另一套界面框架,它试图吸取awt和swing具有的优点,同时避免他们存在的缺点,那便是swt。swt同样遵循最大公分母原则,但与swing不同,swt提供了各个平台的几乎全部控件,但针对不同的平台,swt对该平台不具有的控件采用模拟控件代替,而对于本地已经拥有的控件,则同awt一样使用对等体。显然,swt并不是JDK的标配。


如今,java界面编程的选择都是在swing和swt中进行,awt已经没有考虑的必要。据说swt使用起来比较像MFC,而一想到MFC我就想吐,所以我一开始接触的便是swing,对swing的使用已经有了一定的积累,而swing到目前为止,完全满足我的使用要求,因此,我一直没有对swt做过进一步深入的了解,也无意过多讨论二者的优缺点,只转述一下某位大牛的观点:swing入门难,开发体验满意度和时间成正比,swt入门易,开发体验满意度和时间成反比。


如何使用swing来构建出一个不包含任何功能的纯用户界面,这不是我将要叙述的内容,如何让swing程序高效执行,这才是重点。在这方面,我已经走了不少弯路,大致有以下几点:

1 从主线程上直接访问控件,并且在主线程执行耗时任务,也就是编写了一个单线程的swing程序,后果是界面在执行任务时失去响应,任务简单还好,一旦遇上耗时任务,体验很糟糕。

2 从主线程上直接访问控件,启用多线程执行耗时任务,同时也在多线程上直接访问控件,但对访问部分做了同步处理,这是我在感受到第一种编写swing程序的不足之后做出的改进;后果是通常没有问题;这么做已经基本保证了swing程序的高效性,但最近我终于因此而遇到一些莫名其妙的报错。


当我在任务线程中设置一个JTabbedPane控件的TabTitle时,会偶发性地产生报错:ArrayIndexOutOfIndex,简单说就是我在任务线程中操作的Tab索引超出了索引范围,而事实上,我已经在操作JTabbedPanel之前进行了Tab索引范围验证,因此,这个报错是莫名奇妙的,在调试了好一阵子无果之后,我干脆把任务线程交由EDT线程执行,结果什么问题都没了,我不得不反思我以往的swing程序开发方式并没有遵守的一些规范,其实也就是如何编写高效swing程序的核心所在:

1 swing不是线程安全的,不要试图多线程访问swing控件和其数据模型。

2 swing提供了一个事件调度线程EDT;EDT负责swing控件的绘制和更新、swing事件处理器的调用;任何对swing控件和其数据模型的访问都只应该在EDT上进行,不要在用户线程上直接访问swing控件和其数据模型,即使是主线程。

3 运行于EDT上的任务应该快速完成,这是swing程序高效性的保证;通常来说,对于耗时操作,应该交由独立的任务线程来完成,而非主线程或EDT,而EDT应该仅仅进行与swing控件和其数据模型紧密相关的操作。


这次教训再次说明规范果然有遵守的必要!之后,经过再三的思想斗争,我终于还是苦逼地按照规范把最近的一个swing程序重写了,好几w行代码啊!顺便吐槽一下,按照swing程序的编写规范编写出来的代码真是恶心:到处都是内部类、匿名类、Runnable。

原创粉丝点击