某些人一拍脑袋的事,让我有机会跟Swing干上了,因为项目组没人用这玩意整过这东西,那就只能我硬着头皮上了!有时候人是要有点压力才行的。
***阶段的开发:
准备阶段:工具的选择。用了Netbeans 6,试用了下,感觉画界面还比较容易,但是生成的代码很长,刚开始对Swing很陌生 ,看着netbeans 生成代码很头痛,感觉不是我想要的东西,然后放弃了。然后是VE,因为也只是倒腾了下,没细看。***选择了Jigloo ,但是用了之后才知道他生成的代码也很恶劣......
开发阶段:别熟悉swing 边开发,其中遇到乱七八遭事情一堆,但是因为这个软件的功能是比较简单的,***终于是拿了出来,虽然BUG一堆,但是也算是我的***swing作品,客户感觉效果很不理想(有软件设计方面的,也有技术运用方面的),也就有了下面继续开发的经历了。
主要技术方面问题是,线程的乱用造成死锁,经常造成莫名的假死。
第二阶段的开发:
因为***阶段的开发比较痛苦,所以决定换个语言开发。因为最近RIA比较热,RIA里面的adoble的air也算比较热门的,UI给人感觉很华丽,也自己尝试做过一些DEMO。项目中用的webservice,加密解密操作,文件上传下载都有解决的办法,但是要命的是这个项目中要调用外部程序,air在这方面比较脆弱,google了一把 as 的 fscommand 能调用其他程序,但是 air 竟然不支持这个,后来还是塌塌实实用SWING 吧。
然后又试用了一把VE,感觉现在比上次我用的时候好多了,后来就把Jigloo换 VE了。
摆在眼前的就是如何运用好线程了。又google了一把,找到了swingworker 这个东西拉。从Java SE 6开始引进的SwingWorker能帮你轻松的编写多线程Swing程序,改善你Swing程序的结构,提高界面响应的灵活性,这正是我要的东西。
一个Swing程序中一般有下面三种类型的线程:
◆初始化线程(Initial Thread)
◆UI事件调度线程(EDT)
◆任务线程(Worker Thread)
Swing程序只有一个用EDT,该线程负责GUI组件的绘制和更新,通过调用程序的事件处理器来响应用户交互。所有事件处理都是在EDT上进行的,程序同UI组件和其基本数据模型的交互只允许在EDT上进行,所有运行在EDT上的任务应该尽快完成,以便UI能及时响应用户输入。
Swing编程时应该注意以下几点:
1.从其他线程访问UI组件及其事件处理器会导致界面更新和绘制错误。
2.在EDT上执行耗时任务会使程序失去响应,这会使GUI事件阻塞在队列中得不到处理。
3.应使用独立的任务线程来执行耗时计算或输入输出密集型任务,比如同数据库通信、访问网站资源、读写大树据量的文件。
而我***阶段开发的正是由于没有注意到这点导致整个程序效果不佳。程序中有个事件处理都要访问Web服务,这些服务通常要许多秒后才能响应,在此期间,如果程序在EDT上进行Web服务交互,用户就不能取消搜索或者同界面交互,像这两种都不应该在EDT上运行。
显示了在A和B点之间,EDT不能处理UI事件,AB两点之间代表了程序访Web服务的IO操作时间:
javax.swing.SwingWorker类是Java SE 6中新出现的类,使用SwingWorker,程序能启动一个任务线程来异步查询,并马上返回EDT线程。显示了使用SwingWorker后,事件处理立即返回,允许EDT继续执行后续的UI事件。原先就是都放在EDT上了,效果勉强也就难免了。而使用Swingworker启动一个任务线程就可以灵活响应界面。
下面讲讲他的用法:
SwingWorker的定义如下:public abstract class SwingWorker
SwingWorker是抽象类,因此必须继承它才能执行所需的特定任务。注意该类有两个类型参数:T及V。T是doInBackground和get方法的返回类型,V是publish和process方法要处理的数据类型。
SwingWorker实现以下接口方法:
◆boolean cancel(boolean mayInterruptIfRunning)
◆T get()
◆T get(long timeout, TimeUnit unit)
◆boolean isCancelled()
◆boolean isDone()
SwingWorker实现了所有的接口方法,实际上你仅需要实现以下SwingWorker的抽象方法:protected T doInBackground() throws Exception
doInBackground方法作为任务线程的一部分执行,它负责完成线程的基本任务,并以返回值来作为线程的执行结果。继承类须覆盖该方法并确保包含或代理任务线程的基本任务。不要直接调用该方法,应使用任务对象的execute方法来调度执行。
在获得执行结果后应使用SwingWorker 的get方法获取doInBackground方法的结果。可以在EDT上调用get方法,但该方法将一直处于阻塞状态,直到任务线程完成。***只有在知道结果时才调用get方法,这样用户便不用等待。为防止阻塞,可以使用isDone方法来检验doInBackground是否完成。另外调用方法 get(long timeout, TimeUnit unit)将会一直阻塞直到任务线程结束或超时。获取任务结果的***地方是在done方法内:protected void done()
在doInBackground方法完成之后,SwingWorker调用done方法。如果任务需要在完成后使用线程结果更新GUI组件或者做些清理工作,可覆盖done方法来完成它们。这儿是调用get方法的***地方,因为此时已知道线程任务完成了,SwingWorker在EDT上激活done方法,因此可以在此方法内安全地和任何GUI组件交互。
没必要等到线程完成就可以获得中间结果。中间结果是任务线程在产生***结果之前就能产生的数据。当任务线程执行时,它可以发布类型为V的中间结果,覆盖process方法来处理中间结果。后文还将提供这些方法的更多详细信息。当属性改变时,SwingWorker实例能通知处理器,SwingWorker有两个重要的属性:状态和进程。任务线程有几种状态,以下面SwingWorker.StateValue枚举值来表示:
◆PENDING
◆STARTED
◆DONE
任务线程一创建就处于PENDING状态,当doInBackground方法开始时,任务线程就进入STARTED状态,当doInBackground方法完成后,任务线程就处于DONE状态,随着线程进入各个阶段,SwingWorker超类自动设置这些状态值。你可以添加处理器,当这些属性发生变化来接收通知。
***,任务对象有一个进度属性,随着任务进展时,可以将这个属性从0更新到100标识任务进度,当该属性发生变化时,任务通知处理器进行处理。
我的使用感觉就是,象I/O操作,数据操作,网络操作等耗时的操作放到 doInBackground()中处理,任务执行中而非任务结束时发布数据,要调用publish方法.
publish方法时,SwingWorker类调度process方法。有意思的是process方法是在EDT上面执行,这意味着可以同Swing组件和其模型直接交互。可以实现你在处理任务时,给个进度条提示。
【编辑推荐】