分享
 
 
 

关于Eclipse中UI程序的线程的讨论

王朝other·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

虽然各个操作系统之间的线程机制是不一样的,但是大致是相同的。当用户使用GUI程序时,如果点鼠标或按下键盘上的键等时,操作系统会产生对应的GUI事件,它来决定哪个窗口或程序来接受每一个事件并且放到程序的事件队列中.

任何GUI程序的底层结构就是一个事件循环.程序首先初始化事件循环,并开始循环,这个循环会从事件队列依次接收GUI事件并一一做出相应的反应.程序应该对事件做出快速的反应使程序一直对用户有响应,举个例子,用户点了一下程序里的一个按钮结果程序就没反应了,那么这个程序应该算是一个失败的程序吧.

如果某个UI事件引发了某个需要长时间的事务,那么应该把它放到一个另外的单独的线程中,这样程序的那个事件循环就能够马上回来响应用户的下一个操作.线程是非常复杂的一个主题,如果处理的不好很容易造成死锁等很糟糕的情况.

还好,eclipse为我们开发插件提供了一个方便的UI线程包,大大的简化了很多底层复杂的东西.先看看几个简单的概念.

1.SWT UI线程

SWT用的是操作系统直接支持的线程模式,程序会在主程序里运行一个时间循环并依次在这个线程里响应事件.看下面这段代码,UI线程就是创建Display的那个线程.

public static void main (String [] args) {

Display display = new Display ();

Shell shell = new Shell (display);

shell.open ();

// 开始事件循环

// 关掉窗口后

while (!shell.isDisposed ()) {

if (!display.readAndDispatch ())

display.sleep ();

}

display.dispose ();

}

简单的小程序里,一个UI线程就能够满足需要了。但如果是长时间的操作,你就最好不要用UI线程来做这些事,可以交给Job去做.它其实就是另外启动的线程,也就是等会我要说的非UI线程.

2、Job

Job类由org.eclipse.core.runtime插件提供.它能够让客户程序员轻松的在另外的线程中执行代码。看一个小例子:

Job job = new Job("My First Job") {

protected IStatus run(IProgressMonitor monitor) {

System.out.println("Hello World (from a background job)");

return Status.OK_STATUS;

}

};

job.setPriority(Job.SHORT);

job.schedule(); // start as soon as possible

Job的默认优先级是Job.Long,这里例子中的优先级要比它高,只要调用Job#schedule(),它就会尽快在另外的线程中运行run()中的代码。再看一个小例子:

final Job job = new Job("Long Running Job") {

protected IStatus run(IProgressMonitor monitor) {

try {

while(hasMoreWorkToDo()) {

// do some work

// ...

if (monitor.isCanceled()) return Status.CANCEL_STATUS;

}

return Status.OK_STATUS;

} finally {

schedule(60000); // start again in an hour

}

}

};

job.addJobChangeListener(new JobChangeAdapter() {

public void done(IJobChangeEvent event) {

if (event.getResult().isOK())

postMessage("Job completed successfully");

else

postError("Job did not complete successfully");

}

});

job.setSystem(true);

job.schedule(); // start as soon as possible

monitor是一个进度显示条,它会在运行job时自动显示,如果任务成功运行完成,返回Status.OK_STATUS,如果中途被用户在进度显示条那里中断,就返回Status.CANCEL_STATUS.上面schedule(60000);它是让job每过1小时就自动运行,Job又一个非常强大的功能。然后后面是可以给job添加监听器,

job.setSystem(true);这一句是把这个job设置为系统级别的.如果调用setUser(true),那么就被定义为用户级别的,用户级别和默认级别的job。

在运行时会以UI形式反映出来,如果是用户job,那么会弹出一个进度显示窗口,能让用户选择在后台里运行,下图是一个job自动运行时的效果:

再介绍job常常用到的一个方法Job#join(),系统调用到某个job,调用它的run()方法。再看下面这个例子:

class TrivialJob extends Job {

public TrivialJob() {

super("Trivial Job");

}

public IStatus run(IProgressMonitor monitor) {

System.out.println("This is a job");

return Status.OK_STATUS;

}

}

job的创建和计划如下所示:

TrivialJob job = new TrivialJob();

System.out.println("About to schedule a job");

job.schedule();

System.out.println("Finished scheduling a job");

他们的执行是和时间没关系的,输出可能如下:

About to schedule a job

This is a job

Finished scheduling a job

也可能是:

About to schedule a job

Finished scheduling a job

This is a job

如果希望某个job运行完成后在继续时,可以使用join()方法,join()会一直阻塞到该job运行完。

例子:

TrivialJob job = new TrivialJob();

System.out.println("About to schedule a job");

job.schedule();

job.join();

if (job.getResult().isOk())

System.out.println("Job completed with success");

else

System.out.println("Job did not complete successfully");

上面的代码执行后,输出应该就是这样:

About to schedule a job

This is a job

Job completed with success

Job的功能是很强大的,还有很多功能我以后会介绍,也可以查阅官方帮助文档,这里先把几个常用的问题解决掉。参见:

http://help.eclipse.org/help30/index.jsp?topic=/org.eclipse.platform.doc.isv/guide/runtime_jobs.htm

3、如果在Job中加上改变UI的代码就会失败。原因如下:

如果是在非UI线程中调用UI,SWT就会抛出一个SWTException,要在一个非UI线程改变UI的话有几种技术:

第一种,用:

Display#syncExec(Runnable)或

Diaplay#asyncExec(Runnable)

第二种:

已经开发了另外一种Job,就是UIJob,可以直接在它里面运行改变UI的代码,其实它就是在SWT的asyncExec()方法里运行的.所有继承UIJob的类应该覆写runInUIThread方法而不是run方法。

3.关于进度显示

在Jface中:

org.eclipse.jface.operations包定义了一些接口用来在进度条下运行长时间的任务。可以参见:

http://help.eclipse.org/help30/index.jsp?topic=/org.eclipse.platform.doc.isv/guide/jface_operations.htm

在eclipse插件和RCP开发中:

用户级别的job是互操作性最强的,它不仅能够让用户用Cancel键取消job,而且可以在Detail中展示具体情况,但是注意:

Detail只会在下面两种方法中出现:

IProgressService#busyCursorWhile或

IProgressService#runInUI

1)IProgressService#busyCursorWhile的用法例子:

注意这里的run()中做些和UI无关的事:

IProgressService progressService = PlatformUI.getWorkbench().getProgressService();

progressService.busyCursorWhile(new IRunnableWithProgress(){

public void run(IProgressMonitor monitor) {

//do non-UI work

}

});

效果:

2) IProgressService#runInUI的用法例子:

注意这里的run()中可以做些和UI有关的事。

progressService.runInUI(

PlatformUI.getWorkbench().getProgressService(),

new IRunnableWithProgress() {

public void run(IProgressMonitor monitor) {

//do UI work

}

},

Platform.getWorkspace().getRoot());

效果:

这里最后一个参数可以是null,或者是这个操作的规则,在这里我们是设定运行这个UI操作时锁定工作台.

更加具体的可以参见:

http://help.eclipse.org/help30/index.jsp?topic=/org.eclipse.platform.doc.isv/guide/workbench_jobs.htm

另外,有少数时候,我们不想弹出一个进度条窗口,而是只在最底下的状态栏显示就可以了,很简单,写自己的Job类时,在构造方法里加上一句:

setUser(false);就可以了.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有