Поддержка параллельного выполнения в рабочей среды

Мы знаем, что пользовательский интерфейс JFace предоставляет базовую поддержку отображения индикатора хода выполнения задания в окне диалога (см. Долго выполняемые операции). В разделе Инфраструктура параллельного выполнения мы рассмотрели поддержку параллельного выполнения и долго выполняемых операций в среде. Теперь давайте узнаем, как пользовательский интерфейс платформы расширяет эту инфраструктуру в пакете org.eclipse.ui.progress. Этот пакет содержит пользовательский интерфейс для отображения хода выполнения задания в рабочей среде и предоставляет дополнительную поддержку для заданий, выполняемых в нити пользовательского интерфейса.

Сначала рассмотрим различные типы фоновых операций, а также способы их отображения в пользовательском интерфейсе рабочей среды:


Поскольку в среде возможно разрешено одновременное выполнение нескольких заданий, пользователю требуется следующее:

Служба состояния

Служба состояния рабочей среды (IProgressService) является основным интерфейсом поддержки службы состояния рабочей среды. Ее можно вызвать из рабочей среды и использовать для отображения состояния фоновых операций и операций, выполняемых в нити пользовательского интерфейса. Основным назначением этого класса является обеспечение универсальной поддержки выполняемых операций и устранение необходимости для разработчиков модулей решать, какой механизм следует использовать для отображения состояния в той или иной ситуации. Другим преимуществом является то, что окно состояния, отображаемое таким способом, предоставляет хорошую поддержку для сообщения о том, когда операция блокируется другой операций, и дает возможность разрешить такой конфликт. При возможности долго выполняемые операции следует выполнять используя IProgressService#busyCursorWhile:

   IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
   progressService.busyCursorWhile(new IRunnableWithProgress(){
         public void run(IProgressMonitor monitor) {
         //выполнить работу не пользовательского интерфейса
      }
   });

Этот метод создает курсор хода задания и затем заменяет его окном состояния, если операция будет выполняться дольше указанного времени. Преимуществом данного метода по сравнению с использованием окна состояния является то, что если операция завершится раньше ожидаемого, окно состояния отображаться не будет. Если операция должна обновить пользовательский интерфейс, то соответствующий код можно выполнить с помощью Display.asyncExec или Display.syncExec.

Если операцию следует выполнять полностью в нити пользовательского интерфейса, то следует вызвать IProgressService#runInUI. Этот метод также отображает окно состояния, если операция заблокирована, и передает управление пользователю.

   progressService.runInUI(
      PlatformUI.getWorkbench().getProgressService(),
      new IRunnableWithProgress() {
         public void run(IProgressMonitor monitor) {
            //выполнить работу пользовательского интерфейса
         }
      },
      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 /* сейчас */, true /* использовать курсор "занято" в компоненте */);

Параметры состояния выполнения для заданий

Рабочая среда указывает свойства, связанные с состоянием выполнения, для заданий 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();

Задания рабочей среды

При возможности долго выполняемые операции следует выполнять не в нити пользовательского интерфейса. Однако это невозможно, если целью операции является внесение изменений в пользовательский интерфейс. В разделе Операции с нитями SWT содержатся сведения относительно выполнения таких операций с помощью SWT Display. Рабочая среда задает специальное задание UIJob, выполняющую свой метод run внутри SWT asyncExec. Производные классы UIJob должны использовать метод runInUIThread вместо метода run.

WorkbenchJob расширяет UIJob таким образом, что задание может быть запланировано или выполнено только во время работы рабочей среды. Всегда следует избегать чрезмерной загрузки нити пользовательского интерфейса, так как он не будет обновляться на протяжении выполнения задания пользовательского интерфейса.