Es wurde bereits dargestellt, dass das JFace-Benutzerschnittstellengerüst eine Fortschrittsanzeige für Tasks in einem Dialog grundlegend unterstützt (weitere Details finden Sie unter Lang andauernde Operationen). Unter Infrastruktur für gemeinsamen Zugriff wurde die Laufzeitunterstützung der Plattform für gleichzeitigen Zugriff und lang andauernde Operationen erläutert. An dieser Stelle soll schließlich untersucht werden, wie die Benutzerschnittstelle der Plattform diese Infrastruktur im Paket
org.eclipse.ui.progress noch verbessert. Dieses Paket liefert die Benutzerschnittstelle zur Anzeige des Jobverlaufs in der Workbench und definiert zusätzliche Unterstützung für Jobs, die im Benutzerschnittstellenthread ausgeführt werden.
Betrachten wir zuerst einmal die verschiedenen Arten von Hintergrundoperationen, die ausgeführt werden können, und wie sie in der Workbench-Benutzerschnittstelle angezeigt werden:
Benutzer-Jobs sind solche, die durch den Benutzer eingeleitet worden sind. Die Workbench zeigt Benutzer-Jobs automatisch in einem modalen Fortschrittsdialog an, der eine Schaltfläche enthält, über die der Benutzer die Operation im Hintergrund ausführen und mit seiner Arbeit fortfahren kann. In einer globalen Benutzervorgabe wird angegeben, ob Benutzer-Jobs immer im Hintergrund laufen sollen. Benutzer-Jobs werden als solche in der Job-API mit Hilfe von Job#setUser) unterschieden. Beispiele für Benutzer-Jobs sind Erstellungsprozesse, die Entnahme von Projekten, Synchronisierungen mit dem Repository, das Exportieren von Plug-ins und Suchvorgänge.
Automatisch eingeleitete Jobs sind für den Benutzer von Bedeutung, werden von ihm aber nicht eingeleitet. Diese Jobs werden zwar in der Sicht für Verarbeitungsfortschritt und der Statuszeile angezeigt, im modalen Fortschrittsdialog erscheinen sie während Ihrer Ausführung jedoch nicht. Beispiele hierfür sind automatische Erstellfunktionen und terminierte Synchronisierungen.
Systemoperationen werden nicht durch den Benutzer ausgelöst und können als Detail der Implementierung angesehen werden. Diese Jobs werden durch Einstellung der Markierung 'System' mit Hilfe von Job#setSystem) erstellt. Beispiele für System-Jobs sind Jobs, die Fensterobjekte langsam ausfüllen oder Dekoratoren und Anmerkungen für Sichten berechnen.
In einer gegebenen Umgebung, in der mehrere Dinge gleichzeitig passieren können, benötigt der Benutzer Folgendes:
Eine Meldung, dass ein lang andauernder Prozess gestartet wurde.
Benutzer-Jobs werden dem Benutzer in einem Fortschrittsdialog angezeigt, der eine unmittelbare Rückmeldung erstattet, während automatisch ausgelöste Jobs in der Statuszeile und der Sicht für den Verarbeitungsfortschritt angezeigt werden. Jobs, die eine Komponente beeinflussen, sollten bei der Komponente terminiert oder registriert werden, damit die Workbench dem Benutzer Hinweise darüber liefern kann, das zur Zeit etwas läuft, das die Komponente beeinflusst.
Eine Meldung, dass eine Operation beendet wurde.
Der Benutzer weiß sofort, dass ein Benutzer-Job beendet wurde, da der Fortschrittsdialog geschlossen wird. Für die anderen Jobtypen stehen mehrere Feedbackmechanismen zur Verfügung. Wenn der Job bei einer Komponente terminiert oder registriert wurde, gibt der Fortschrittshinweis der Komponente Rückmeldung, wenn er beendet wurde. Gibt ein Job einen Fehler zurück, so erscheint unten rechts in der Statuszeile ein Fehleranzeiger, der einen Hinweis über den aufgetretenen Fehler enthält.
Eine Meldung über interessante neue Ergebnisse oder neue Informationen, ohne dass der Fokus verschoben wird, indem ein Dialog angezeigt wird.
Ein Benutzer-Job kann dem Benutzer die Ergebnisse bei Beendigung der Operation direkt anzeigen. Für die anderen Jobtypen wird empfohlen, den Benutzer nicht durch einen Dialog, der die Ergebnisse anzeigt, zu unterbrechen. Zum Beispiel wenn der Job beginnt und die Ergebnisse in dieser Ansicht gezeigt werden, ohne den Arbeitsablauf des Benutzers zu unterbrechen. Darüber hinaus können Sie dem Job Job-Eigenschaften hinzufügen, um anzuzeigen, dass die Fortschrittssicht beibehalten werden soll und der Job über eine Aktion verfügt, die die Ergebnisse anzeigt. In diesem Fall erscheint eine Warnmeldung in der unteren rechten Ecke der Statuszeile, wenn ein Job in der Fortschrittssicht bleibt und Ergebnisse hat, die dem Benutzer angezeigt werden können.
Ein allgemeines Gefühl, die Kontrolle über alle ausgeführten Prozesse zu haben, sowie die Fähigkeit, Hintergrundoperationen zu überwachen und abzubrechen.
Benutzer-Jobs bieten dem Benutzer die beste Form der Kontrolle, da sie leicht abgebrochen werden können und über die Registerkarte Details des Fortschrittdialogs einen deutlichen Hinweis auf möglicherweise blockierende oder gleichzeitige Operationen liefern. Beachten Sie, dass ein erweiterter Fortschrittdialog mit dem Bereich Details nur angezeigt wird, wenn Benutzer IProgressService#busyCursorWhile
oder IProgressService#runInUI aufrufen.
Darüber hinaus bietet die Sicht für Verarbeitungsfortschritt Zugriff auf laufende Jobs.
Einheitliche Erstellung von Berichten über den Verarbeitungsfortschritt von allen installierten Plug-ins.
Ein Vorteil der Verwendung der Fortschrittservice-API besteht darin, dass Benutzer an ein konsistentes Fortschrittverhalten gewöhnt werden.
Der Fortschrittservice der Workbench (IProgressService) ist die Hauptschnittstelle zur Fortschrittunterstützung der Workbench. Er kann aus der Workbench abgerufen und dann dazu verwendet werden, den Fortschritt für Operationen sowohl im Hintergrund als auch im Benutzerschnittstellenthread anzuzeigen. Die Hauptaufgabe dieser Klasse ist die Bereitstellung eines einzelnen Zugriffspunktes für laufende Operationen, wodurch Plug-in-Entwickler nicht mehr entscheiden müssen, welcher Mechanismus in einer bestimmten Situation für die Fortschrittsanzeige verwendet werden soll. Ein weiterer Vorteil besteht darin, dass der über diese Methoden dargestellte Fortschrittdialog eine gute Unterstützung für die Anzeige, ob eine Operation durch eine andere blockiert wird, darstellt. Darüber hinaus bietet er dem Benutzer die Möglichkeit, den Konflikt zu beheben. Wenn möglich, sollten lang andauernde Operationen immer über IProgressService#busyCursorWhile ausgeführt werden:
IProgressService progressService = PlatformUI.getWorkbench().getProgressService(); progressService.busyCursorWhile(new IRunnableWithProgress(){ public void run(IProgressMonitor monitor) { //do non-UI work } });
Diese Methode zeigt zunächste einen aktiven Cursor an und ersetzt diesen dann durch einen Fortschrittdialog, wenn die Operation länger dauert, als in einem vorbestimmten Schwellenzeitwert angegeben. Der Vorteil dieser Methode im Gegensatz zur Verwendung eines Fortschrittdialogs besteht darin, dass der Fortschrittdialog für schnell durchlaufende Operationen nicht angezeigt werden würde. Wenn Ihre Operation die Benutzerschnittstelle aktualisieren muss, können Sie immer Display.asyncExec oder Display.syncExec verwenden, um den Code auszuführen, der die Benutzerschnittstelle ändert.
Wenn eine Operation vollständig im Benutzerschnittstellenthread ausgeführt werden soll, sollten Sie IProgressService#runInUI verwenden. Diese Methode zeigt auch einen Fortschrittdialog an, wenn die Operation blockiert ist und ermöglicht dem Benutzer so die Kontrolle.
progressService.runInUI( PlatformUI.getWorkbench().getProgressService(), new IRunnableWithProgress() { public void run(IProgressMonitor monitor) { //do UI work } }, Platform.getWorkspace().getRoot());
Der dritte Parameter kann den Wert Null oder eine Zeitplanungsregel für die Operation annehmen. In diesem Beispiel wird das Stammverzeichnis des Arbeitsbereichs angegeben, wodurch der Arbeitsbereich gesperrt wird, während diese Benutzerschnittstellenoperation ausgeführt wird..
Sie können den Fortschrittservice auch mit dem Symbol einer Jobfamilie registrieren, damit in der Sicht für Verarbeitungsfortschritt das Symbol neben dem laufenden Job angezeigt wird. Im folgenden Beispiel wird die automatische Erstellfunktion dem entsprechenden Symbol zugeordnet:
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 bietet API für die Zeitplanung von Jobs, die während der Ausführung die Darstellung einer Workbench-Komponente ändern. Wenn Ihr Plug-in Hintergrundoperationen ausführt, die den Status einer Komponente beeinflussen, können Sie den Job über die Komponente terminieren, so dass der Benutzer eine Rückmeldung erhält, dass die Komponente ausgelastet ist. Hier ein Beispiel:
IWorkbenchSiteProgressService siteService = (IWorkbenchSiteProgressService)view.getSite().getAdapter(IWorkbenchSiteProgressService.class); siteService.schedule(job, 0 /* now */, true /* use the half-busy cursor in the part */);
Die Workbench definiert fortschrittsbezogene Eigenschaften für Jobs in IProgressConstants . Diese können verwendet werden, um zu kontrollieren, wie ein Job in der Verarbeitungsfortschritt-Ansicht gezeigt wird. Hierüber kann der Sicht für Verarbeitungsfortschritt mitgeteilt werden, dass Ihr Job nach Beendigung in der Sicht erhalten bleiben soll (IProgressConstants#KEEP_PROPERTY) oder dass nur ein Job auf einmal in der Sicht angezeigt werden soll (IProgressConstants#KEEPONE_PROPERTY). Sie können einem Job auch eine Aktion zuordnen (IProgressConstants#ACTION_PROPERTY). Wenn einem Job eine Aktion zugeordnet ist, wird in der Sicht für Verarbeitungsfortschritt ein Hyperlink angezeigt, über den der Benutzer die Aktion ausführen kann. Sie können auch feststellen, ob ein Benutzer-Job zur Zeit in einem Fortschrittdialog angezeigt wird (IProgressConstants#PROPERTY_IN_DIALOG). In der rechten unteren Ecke der Statuszeile wird ein Hinweis angezeigt, wenn eine Aktion zur Verfügung steht. Das folgende Beispiel verwendet diese Eigenschaften:
Job job = new Job("Do Work") { public IStatus run(IProgressMonitor monitor) { // eine Arbeit ausführen. // Den beendeten Job nur in der Fortschrittsansicht behalten, wenn er nicht im Fortschrittsdialog ausgeführt wird 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();
Wenn möglich, sollten lang andauernde Operationen außerhalb des Benutzerschnittstellenthreads ausgeführt werden. Dies kann allerdings nicht immer vermieden werden, wenn Zweck der Operation eine Aktualisierung der Benutzerschnittstelle ist. Hinweise zur Verwendung von SWT-Threads erklärt, wie dies über die SWT-Anzeige bewerkstelligt werden kann. Die Workbench definiert einen speziellen Job namens UIJob, dessen Methode 'run' innerhalb einer SWT-asyncExec läuft. Unterklassen von UIJob sollten die Methode runInUIThread statt der Methode run implementieren.
WorkbenchJob erweitert UIJob, so dass der Job nur terminiert oder ausgeführt werden kann, wenn die Workbench läuft. Sie sollten wie immer übermäßige Nutzung des Benutzerschnittstellenthreads vermeiden, da die Benutzerschnittstelle während der Ausführung eines Benutzerschnittstellen-Jobs nicht aktualisiert wird.