我討論的進度條主要是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()就解決了!
客戶虐我千百遍,我待客戶如初戀!