工作台并行支持

我们已经知道,JFace 用户界面框架对于在对话框中显示任务进度提供了基本支持(有关详细信息,请参阅长时间运行的操作)。在并行基础结构中,我们查看了并行和长时间运行操作的平台运行时支持。现在,我们将在 org.eclipse.ui.progress 包中查看平台用户界面是如何增强此基础结构的。此包提供了用于在工作台中显示作业进度的用户界面,并且对于在用户界面线程中运行的作业定义更多支持。

首先,让我们看一看可能正在运行的不同种类的后台操作及它们在工作台用户界面中如何显示:


假定一个环境中有几项操作可能会同时发生,则用户需要:

进度服务

工作台进度服务(IProgressService)是与工作台进度支持的主要接口。可以从工作台中获得进度服务,然后使用它来显示后台操作的进度和在用户界面线程中运行的操作的进度。此类的主要用途是对正在运行的操作提供“一站式采购机制”,从而使插件开发者无需决定应该使用哪种机制来显示给定情况下的进度。它的另一个优点是,使用这些方法显示的进度对话框能够很好地指示一个操作何时被另一个操作阻塞了,并且使用户能够控制冲突的解决。应该尽可能使用 IProgressService#busyCursorWhile 来运行长时间运行的操作:

   IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
   progressService.busyCursorWhile(new IRunnableWithProgress(){
         public void run(IProgressMonitor monitor) {
         //do non-UI work
      }
   });

此方法最初将显示一个繁忙光标,当操作的持续时间超过指定的时间阈值时,就会将该光标替换为进度对话框。与使用进度对话框比较起来,这种方法的优点在于,如果一个操作的运行时间较短,就不会显示进度对话框。如果操作必须更新用户界面,则您始终可以使用 Display.asyncExecDisplay.syncExec 来运行用于修改用户界面的代码。

如果一个操作必须作为一个整体在用户界面线程中运行,则应该使用 IProgressService#runInUI。如果操作被阻塞,这种方法还会显示一个进度对话框,并为用户提供了控制权。

   progressService.runInUI(
      PlatformUI.getWorkbench().getProgressService(),
      new IRunnableWithProgress() {
         public void run(IProgressMonitor monitor) {
            //do UI work
         }
      },
      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) {
         // do some work.  
         // Keep the finished job in the progress view only if it is not running in the progress dialog
         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() {
         // show the results
      }
   };
   job.setProperty(IProgressConstants.ACTION_PROPERTY, gotoAction);
   job.setUser(true);
   job.schedule();

工作台作业

应该尽可能在用户界面线程外部执行长时间运行的操作。但是,当该操作的目的是更新用户界面时,就不能始终都这样做。SWT 线程技术问题说明可以如何使用 SWT Display 来做到这一点。工作台定义了一个特殊作业 - UIJob,它的 run 方法将在 SWT asyncExec 内部运行。UIJob 的子类应该实现 runInUIThread 方法而不是 run 方法。

WorkbenchJob 扩展 UIJob,以便仅当工作台正在运行时才能调度或运行作业。通常,应该避免在用户界面线程中工作时间过长,因为在执行用户界面作业期间用户界面将不会刷新。