工作台並行支援

我們已經看到 JFace UI 架構提供了在對話框中顯示作業進度的基本支援(請參閱長時間執行的作業,以取得詳細資料)。在並行基礎架構中,我們也檢視了並行和長時間執行的作業的平台執行時期支援。現在,我們要檢視在 org.eclipse.ui.progress 套件中,平台 UI 如何加強這個基礎架構。這個套件提供了在工作台中顯示工作進度的 UI,也定義了 UI 執行緒中執行之工作的其他支援。

首先,讓我們查看可能會執行的不同類型背景作業,以及它們在工作台使用者介面中的顯示方式。


在給定可能同時發生許多事項的環境之後,使用者需要下列項目:

進度服務

工作台進度服務 (IProgressService) 是工作台進度支援的主要介面。它可以從工作台中取得,之後,便可用來顯示背景作業以及在 UI 執行緒中執行的作業的進度。這個類別的主要用途是提供執行中的作業的單點購物功能,外掛程式開發人員不需要決定在給定狀態中應該用哪個機制來顯示進度。另一個好處是這些方法所顯示的進度對話框,能夠很好地支援某項作業為其他作業所阻斷時的指示, 同時也提供解決衝突的使用者控制能力。如果可能的話,應該利用 IProgressService#busyCursorWhile 來執行長時間執行的作業:

   IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
   progressService.busyCursorWhile(new IRunnableWithProgress(){
         public void run(IProgressMonitor monitor) {
         //執行非 UI 工作
      }
   });

這個方法最初會建立一個工作中游標,如果作業持續時間超出指定的時間臨界值,就會用一個對話框來取代它。這個方法比使用進度對話框好,因為如果作業的執行時間較短,就不會顯示進度對話框。如果您的作業必須更新 UI,您一律可以使用 Display.asyncExecDisplay.syncExec 來執行修改 UI 的程式碼。

如果作業必須完全在使用者介面執行緒中執行,則應該使用 IProgressService#runInUI。如果作業暫停執行,這個方法也會顯示一個進度對話框,使用者可以進行控制,讓使用者可以進行控制。

   progressService.runInUI(
      PlatformUI.getWorkbench().getProgressService(),
      new IRunnableWithProgress() {
         public void run(IProgressMonitor monitor) {
            //執行 UI 工作
         }
      },
      Platform.getWorkspace().getRoot());

第三個參數可以是空值,或是作業的排程規則。在本例中,我們指定工作區的根目錄,基本上,當這項使用者介面作業執行時,這會鎖定工作區。

您也可以用進度服務來登錄工作系列的圖示,使進度視圖能夠在執行中的工作旁顯示這個圖示。以下是顯示自動建置工作系統如何與其圖示產生關聯的範例:

   IProgressService service = PlatformUI.getWorkbench().getProgressService();
   ImageDescriptor newImage = IDEInternalWorkbenchImages.getImageDescriptor(
      IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC);
   service.registerIconForFamily(newImage, ResourcesPlugin.FAMILY_MANUAL_BUILD);
   service.registerIconForFamily(newImage, ResourcesPlugin.FAMILY_AUTO_BUILD);

顯示組件在工作中

IWorkbenchSiteProgressService 包括一個 API,當工作在執行中時,可排定其他工作來變更工作台組件的外觀。如果您的外掛程式正在執行會影響某個組件的狀態之背景作業,您可以透過這個組件來排定工作,使用者會得到組件在工作中的回饋。以下是一個範例:

   IWorkbenchSiteProgressService siteService =
      (IWorkbenchSiteProgressService)view.getSite().getAdapter(IWorkbenchSiteProgressService.class);
   siteService.schedule(job, 0 /* now */, true /* use the half-busy cursor in the part */);

工作的進度內容

工作台在 IProgressConstants 中定義工作的進度相關內容。這可用來控制工作在進度視圖中的顯示方式。它們可用來告訴進度視圖在工作完成之後將工作保留 (IProgressConstants#KEEP_PROPERTY) 在視圖中, 或每次只在視圖中保留一個 (IProgressConstants#KEEPONE_PROPERTY) 工作。您也可以建立某個動作 (IProgressConstants#ACTION_PROPERTY) 與某項工作的關聯性。當工作有相關的動作時,進度視圖會顯示一個超鏈結,供使用者執行動作。您也可以瞭解某項使用者工作目前是否出現在進度對話框 (IProgressConstants#PROPERTY_IN_DIALOG) 中。當有可用的動作時,狀態行右下角會出現提示。下列使用這些內容:

   Job job = new Job("Do Work") {
      public IStatus run(IProgressMonitor monitor) {
         // 執行部分工作。
         // 如果沒有在進度對話框中執行的話,便只將已完成的工作保留在進度視圖中
         Boolean inDialog = (Boolean)getProperty(IProgressConstants.PROPERTY_IN_DIALOG);
         if(!inDialog.booleanValue())
            setProperty(IProgressConstants.KEEP_PROPERTY, Boolean.TRUE);
      }
   };
   job.setProperty(IProgressConstants.ICON_PROPERTY, Plugin.getImageDescriptor(WORK_IMAGE));
   IAction gotoAction = new Action("Results") {
public void run() {
   // 顯示結果
      }
   };
   job.setProperty(IProgressConstants.ACTION_PROPERTY, gotoAction);
   job.setUser(true);
   job.schedule();

工作台工作

可能的話,應該在 UI 執行緒之外執行長時間執行的作業。不過,當作業目的是更新 UI 的話,不一定能避免這個情況。SWT 執行緒作業問題說明如何利用 SWT Display 來做到這一點。工作台會定義一個特殊工作 UIJob,它的 run 方法是在 SWT asyncExec 內執行的。UIJob 的子類別應該實作 runInUIThread 方法,而不是 run 方法。

WorkbenchJob 繼承 UIJob,因此,工作台必須在執行中,才能排定或執行這個工作。同樣地,在 UI 執行緒中應該避免過量的工作,因為在 UI 工作的持續時間內,不會自動更新 UI。