Мы знаем, что пользовательский интерфейс JFace предоставляет базовую поддержку отображения индикатора хода выполнения задания в окне диалога (см. Долго выполняемые операции). В разделе Инфраструктура параллельного выполнения мы рассмотрели поддержку параллельного выполнения и долго выполняемых операций в среде. Теперь давайте узнаем, как пользовательский интерфейс платформы расширяет эту инфраструктуру в пакете
org.eclipse.ui.progress. Этот пакет содержит пользовательский интерфейс для
отображения хода выполнения задания в рабочей среде и предоставляет дополнительную
поддержку для заданий, выполняемых в нити пользовательского интерфейса.
Сначала рассмотрим различные типы фоновых операций, а также способы их отображения в пользовательском интерфейсе рабочей среды:
Задания, запущенные пользователем - это те задания, которые были явным образом активированы пользователем. Рабочая среда автоматически отображает пользовательские задания в модальном окне состояния, в котором имеется кнопка, позволяющая запустить операцию в фоновом режиме и продолжить работу. С помощью глобальных параметров можно указать, следует ли всегда выполнять пользовательские задания в фоновом режиме. Пользовательские задания различаются таким образом в API заданий с поддержкой (Job#setUser). В качестве примеров пользовательских заданий можно привести создание, изъятие проекта, синхронизацию с хранилищем, экспорт модуля и поиск.
Автоматически запущенные задания имеют определенное значение для пользователя, но не были запущены пользователем. Такие задания отображаются в окне состояния и в строке состояния, но при их работе не показывается модальное окно состояния. В качестве примеров можно привести автоматическую компоновку и запланированную синхронизацию.
Системные операции - это операции, не запущенные пользователем, которые можно рассматривать как элементы реализации платформы. Эти задания создаются путем установки системного флага (Job#setSystem). Примерами системных заданий могут служить задания, предоставляющие данные виджетам или просчитывающие оформление и аннотации для панелей.
Поскольку в среде возможно разрешено одновременное выполнение нескольких
заданий, пользователю требуется следующее:
Указание запуска долго выполняемой операции.
Пользовательские задания отображаются в окне состояния, тогда как автоматически запущенные задания отображаются в строке состояния и панели состояния.
Задания, связанные с компонентом, должны быть запланированы или
зарегистрированы в компоненте. Таким образом, рабочая среда уведомляет пользователя о
выполнении заданий, связанных с компонентом.
Указание завершения операции.
Пользователь может узнать о завершении операции по закрытию окна диалога состояния. Для
заданий, не запущенных пользователем, предусмотрены механизмы обратной связи. Если
задание было запланировано или зарегистрировано вместе с
компонентом, то компонент сможет сообщить о его завершении. Если задание возвращает
ошибку, появится индикатор ошибки в правом нижнем углу строки состояния.
Отображение новых результатов или новой информации без отвлекающих окон диалогов.
Пользовательское задание может непосредственно отобразить результаты по завершении
операции. Задания,
запущенные не пользователем, не должны прерывать пользователя и отображать
результаты с помощью окна диалога. Например, для отображения результатов при запуске
задания может открываться панель, не прерывающая поток операций пользователя. Кроме того,
можно указать свойства задания, в соответствии с которыми
это задание должно будет отображаться на панели состояния и предоставлять результаты. В этом
случае если на панели состояния остаются некоторые задания, которые должны предоставить
пользователю результаты работы, в нижнем правом углу строки состояния будет отображен
символ предупреждения.
Общее ощущение управления заданиями и возможность отслеживать и отменять фоновые операции.
Пользователь обладает максимальным контролем над пользовательскими заданиями, так как
их легко отменить, и они предоставляют подробную информацию о блокирующих или параллельно
выполняемых операциях с помощью вкладки Сведения. Обратите внимание, что
расширенное окно состояния с областью, в котором предусмотрена область
Сведения, отображается только в том случае, если модули применяют IProgressService#busyCursorWhile
или IProgressService#runInUI. Кроме того, окно состояния предоставляет доступ к выполняемым заданиям.
Согласованное отображение информации о состоянии выполнения всех установленных модулей.
Преимуществом использования API службы состояния является то, что пользователи могут постоянно наблюдать за состоянием.
Служба состояния рабочей среды (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 таким образом, что задание может быть запланировано или выполнено только во время работы рабочей среды. Всегда следует избегать чрезмерной загрузки нити пользовательского интерфейса, так как он не будет обновляться на протяжении выполнения задания пользовательского интерфейса.