大梦想家

5年开发工程师,2年实施经理,X年售前顾问,......
数据加载中……
JFace进度条使用经验一则

    我讨论的进度条主要是JFace的进度条,RCP已经提供了完善的Job组件,为什么还要用JFace的进度条呢?原因是我要在登陆界面上做进度处理,也就是使用Eclipse3.3提供的AbstractSplashHandler特性,可以将原有的启动画面替换成为一个登陆界面,启动这个登陆界面时,Eclipse的Platform此时还没有启动,所以不能使用RCP本身的Job组件了。

    由于是一个检测服务器是否联通的测试,所以并不知道测试的真实时间,所以就是要使用“傻瓜进度条”了,也就是反复走的进度条陈刚的代码如下:

button.addSelectionListener(new SelectionAdapter() {
            private boolean stopFlag;// 停止标志

            private void go() {
                for (int i = 0; i < 10; i++) {// 循环10次,每次间隔一秒
                    System.out.println("第" + (i + 1) + "个任务执行完毕");
                    if (stopFlag) {// 监控是否要让停止后台任务
                        System.out.println("被中断了");
                        return;
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (Throwable t) {}
                }
                stopFlag = true;// 执行完毕后把标志位设为停止,好通知给进度框
                System.out.println("全部任务执行完毕");
            }

            public void widgetSelected(SelectionEvent e) {
                stopFlag = false;// 每次都设初值为false
                new Thread() {// 把后台任务放到一个新开线程里执行
                    public void run() {
                        go();
                    }
                }.start();
                showProgressDialog();// 打开一个进度框
            }

            private void showProgressDialog() {
                IRunnableWithProgress runnable = new IRunnableWithProgress() {
                    public void run(IProgressMonitor monitor) {
                        monitor.beginTask("正在执行中......", 30);
                        int i = 0;
                        while (true) {
                            // 监听是否单击了进度框的“取消”按钮,stopFlag则是监听后台任务是否停止
                            if (monitor.isCanceled() || stopFlag) {
                                stopFlag = true; // 单击了“取消”按钮要设标志位为停止,好通知后台任务中断执行
                                break;// 中断处理
                            }
                            // i到30后清零。并将进度条重新来过
                            if ((++i) == 30) {
                                i = 0;
                                monitor.beginTask("正在执行中......", 30);
                            }
                            // 进度条每前进一步体息一会,不用太长或太短,时间可任意设。
                            try {
                                Thread.sleep(99);
                            } catch (Throwable t) {}
                            monitor.worked(1);// 进度条前进一步
                        }
                        monitor.done();// 进度条前进到完成
                    }
                };
                try {
                    new ProgressMonitorDialog(s).run(true, true, runnable);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

 

    主要是使用两个线程交替使用,第一个线程处理业务,第二个线程监控第一个线程查看它是否结束,如果结束或者被点击cancele则停止进度条的进程,如果一直没有关闭的指令,则反复开始---累加---结束---开始---累加---结束。

    我们几乎是把陈刚的代码原原本本的抄袭了一下,仅仅是替换了go()中的内容,但是发现一个问题

new ProgressMonitorDialog(s).run(true, true, runnable);
使用此句的话,JFace的线程永远不会启动;

替换为

new ProgressMonitorDialog(s).run(false, true, runnable);
使用此句的话,JFace的线程可以启动,运行正常,但是cancele不能响应,UI界面完全卡死!

    第一个参数的名字fork~乍看去,什么意思都没有,但是看看API才发现内藏很大的玄机,如果为true则此线程为一个非UI线程,大家知道非UI线程是不会阻塞UI的;如果为false则此线程为一个UI线程,大家也知道UI线程如果使用不当很容易阻塞UI的。

    关键的问题是我们和陈刚的代码几乎一摸一样他的进度条就启动,我的进度条就不启动!为什么?(这点至今不明白!)

    详查API发现如果fork为false的时候还是另有洞天的:

This implementation of IRunnableContext#run(boolean, boolean, IRunnableWithProgress) runs the given IRunnableWithProgress using the progress monitor for this progress dialog and blocks until the runnable has been run, regardless of the value of fork. The dialog is opened before the runnable is run, and closed after it completes. It is recommended that fork is set to true in most cases. If fork is set to false, the runnable will run in the UI thread and it is the runnable's responsibility to call Display.readAndDispatch() to ensure UI responsiveness.

API中说的很明白,如果fork为false时需要在线程中调用Display.readAndDispatch()方法,以避免UI被阻塞!

大家如果在JFace的开发中如果使用了进度条,发现UI被阻塞的话,就想想我哦!!!呵呵只用在进程中调用一下Display.readAndDispatch()就解决了!



客户虐我千百遍,我待客户如初恋!

posted on 2008-02-29 08:47 阿南 阅读(3812) 评论(6)  编辑  收藏 所属分类: Eclipse-SWT个人原创

评论

# re: JFace进度条使用经验一则 2008-02-29 10:12 香草的天空

这一点和win32api很像
  回复  更多评论    

# re: JFace进度条使用经验一则 2008-02-29 13:43 Matthew Chen

我把你的代码拷过来,用new ProgressMonitorDialog(s).run(true, true, runnable); 好像可以用啊,进度条走了几次就停下来,cancel也可以,没出什么问题啊,我用swt3.3
  回复  更多评论    

# re: JFace进度条使用经验一则 2008-02-29 17:26 阿南

首先我上面贴的代码是没有问题的!
其次多看几遍
“我讨论的进度条主要是JFace的进度条,RCP已经提供了完善的Job组件,为什么还要用JFace的进度条呢?原因是我要在登陆界面上做进度处理,也就是使用Eclipse3.3提供的AbstractSplashHandler特性,可以将原有的启动画面替换成为一个登陆界面,启动这个登陆界面时,Eclipse的Platform此时还没有启动,所以不能使用RCP本身的Job组件了。”
  回复  更多评论    

# re: JFace进度条使用经验一则 2008-03-01 10:01 pice

在go()方法中你用一个for循环来假设正在执行的业务调用,如果go方法中就一个方法调用,但是这个方法执行时间比较长。private void go() {
dbSelectList();//查询数据库,查询时间大约10秒
stopFlag = true;// 执行完毕后把标志位设为停止,好通知给进度框
System.out.println("全部任务执行完毕");
}
这时进度条的cancel按钮就不起作用了,不管是否点击cancel按钮dbSelectList()方法都将执行完毕后进度条才注销。就算是重写进度条的cancelPressed()方法关闭UI线程使得进度条界面“消失”,但是dbSelectList()方法还是会继续执行完。
进度条能应对这样的情况吗?
  回复  更多评论    

# re: JFace进度条使用经验一则 2008-03-02 14:46 xifu

比javascript简约啊
  回复  更多评论    

# re: JFace进度条使用经验一则 2010-05-09 10:38 灵均

做个手机收发短信软件
  回复  更多评论    

只有注册用户登录后才能发表评论。


网站导航: