Wiadomo już, że środowisko interfejsu użytkownika JFace udostępnia podstawową
obsługę wyświetlania postępu czynności w oknie dialogowym (szczegółowe
informacje na ten temat zawiera sekcja
Długotrwałe operacje). W sekcji
Infrastruktura współbieżności omówiono obsługę
środowiska wykonawczego platformy w zakresie współbieżności i długotrwałych
operacji. Tematem niniejszej sekcji jest sposób rozszerzenia tej infrastruktury
przez interfejs użytkownika platformy za pomocą pakietu
org.eclipse.ui.progress.
Pakiet ten umożliwia wyświetlanie postępu zadań w środowisku roboczym oraz
definiuje dodatkową obsługę dla zadań uruchamianych w wątku interfejsu
użytkownika.
Istnieją różne rodzaje operacji działających w tle i różne sposoby wyświetlania informacji o nich przez interfejs użytkownika środowiska roboczego:
Zadania inicjowane przez użytkownika są wyzwalane przez działania użytkownika. Środowisko robocze automatycznie wyświetli zadania użytkownika w modalnym oknie dialogowym postępu, w którym dostępny jest przycisk umożliwiający użytkownikowi uruchomienie operacji w tle i kontynuowanie pracy. Istnieje globalna preferencja, która pozwala określić, czy zadania użytkownika powinny zawsze być uruchamiane w tle. Zadania użytkownika są oznaczane przez interfejs API zadań za pomocą metody Job#setUser. Przykłady zadań użytkownika obejmują budowanie, pobieranie projektu z repozytorium, synchronizowanie elementów z repozytorium, eksportowanie modułu dodatkowego oraz wyszukiwanie.
Zadania wyzwalane automatycznie mają określone znaczenie dla użytkowników, ale nie są przez nich bezpośrednio inicjowane. Zadania te są wyświetlane w widoku postępu i w wierszu statusu, ale po ich uruchomieniu nie jest wyświetlane modalne okno dialogowe postępu. Przykłady takich zadań to między innymi automatyczne budowanie i zaplanowana synchronizacja.
Operacje systemowe nie są wyzwalane przez użytkownika; zależą od implementacji platformy. Zadania te tworzy się, ustawiając flagę systemową przy użyciu metody Job#setSystem. Przykłady zadań systemowych obejmują zadania, które wolno zapełniają widgety lub wyliczają dekoracje i adnotacje dla widoków.
W środowisku, w którym wiele zadań może być wykonywanych jednocześnie,
użytkownik powinien mieć dostęp do:
Informacji o uruchomieniu długotrwałej operacji.
Zadania użytkownika są wyświetlane w oknie dialogowym postępu, co zapewnia
natychmiastowe informacje zwrotne. Zadania wyzwalane automatycznie są natomiast
wyświetlane w wierszu statusu i w widoku postępu. Ponadto zadania, które
mają wpływ na część, powinny być zaplanowane
lub zarejestrowane z tą częścią, dzięki czemu środowisko robocze będzie
mogło informować użytkownika o uruchomionych operacjach, które mają wpływ na część.
Informacji o zakończeniu operacji.
Użytkownik od razu wie, kiedy zadanie użytkownika kończy się, ponieważ zostaje
wtedy zamknięte okno dialogowe postępu. Natomiast dla innych zadań dostępnych jest
kilka mechanizmów dostarczania informacji zwrotnych. Gdy zadanie
zostało zaplanowane lub zarejestrowane wraz z
częścią, o jego zakończeniu poinformuje wskazówka postępu dla części. Gdy
zadanie zwróci błąd, w prawym dolnym rogu wiersza statusu zostanie wyświetlona
wskazówka z informacją o wystąpieniu błędu.
Informacji o ciekawych nowych wynikach lub informacjach, bez potrzeby przenoszenia aktywności do okien dialogowych wyświetlanych przez operacje wykonywane w tle.
Zadanie użytkownika może po zakończeniu operacji bezpośrednio wyświetlić wyniki. W
przypadku zadań innych niż zadania użytkownika nie zaleca się przerywać pracy użytkownika
wyświetlaniem okna dialogowego. Można na przykład uruchamiając zadanie otworzyć widok,
w którym będą wyświetlane wyniki bez przerywania pracy użytkownika.
Ponadto warto skorzystać z właściwości
zadania, które są do niego dodawane w celu wskazania, że ma ono być
wyświetlane w widoku postępu, i że ma akcję pozwalającą na wyświetlanie
wyników. W takim przypadku gdy zadanie pozostaje w widoku postępu i ma wyniki do wyświetlenia,
w prawym dolnym rogu wiersza postępu zostanie wyświetlony wskaźnik ostrzeżenia.
Ogólnego poczucia kontroli nad uruchamianymi operacjami z możliwością monitorowania i anulowania operacji wykonywanych w tle.
Zadania użytkownika zapewniają najwyższy stopień kontroli, ponieważ można je
w łatwy sposób anulować, a także informują o wykonywanych operacjach blokowania
i operacjach współbieżnych na karcie Szczegóły w oknie dialogowym
postępu. Należy zwrócić uwagę, że rozszerzone okno dialogowe postępu z obszarem
Szczegóły jest wyświetlane tylko w modułach dodatkowych korzystających z
interfejsu IProgressService#busyCursorWhile
lub interfejsu IProgressService#runInUI.
Ponadto w widoku postępu możliwy jest dostęp do uruchomionych zadań.
Spójnego sposobu powiadamiania o postępie przez wszystkie zainstalowane moduły dodatkowe.
Zaletą korzystania z interfejsu API usługi postępu jest spójny sposób
przedstawiania postępu użytkownikowi.
Usługa postępu w środowisku roboczym (IProgressService) to główny interfejs obsługi wyświetlania postępu w środowisku roboczym. Można ją uzyskać ze środowiska roboczego, a następnie użyć do wyświetlania postępu zarówno operacji wykonywanych w tle, jak i operacji uruchamianych w wątku interfejsu użytkownika. Głównym celem tej klasy jest zapewnienie kompleksowej obsługi uruchamianych operacji i zwolnienie programistów modułów dodatkowych z obowiązku decydowania, który mechanizm powinien być używany do wyświetlania postępu w danej sytuacji. Inną zaletą jest to, że okno dialogowe postępu wyświetlane przy użyciu tych metod zapewnia sygnalizację sytuacji, w których jedna operacja jest blokowana przez inną, i przekazuje sterowanie użytkownikowi w celu rozwiązania konfliktu. O ile to możliwe, długotrwałe operacje powinny być uruchamiane przy użyciu interfejsu IProgressService#busyCursorWhile:
IProgressService progressService = PlatformUI.getWorkbench().getProgressService(); progressService.busyCursorWhile(new IRunnableWithProgress(){ public void run(IProgressMonitor monitor) { //wykonanie pracy niezwiązanej z interfejsem użytkownika } });
Metoda ta powoduje początkowo wyświetlenie kursora zajętości i zastępuje go oknem dialogowym postępu, gdy operacja trwa dłużej niż określony limit czasu. Zaletą tej metody w porównaniu z korzystaniem z okna dialogowego postępu jest to, że dla krótkotrwałych operacji okno dialogowe postępu nie będzie wyświetlane. Jeśli operacja musi aktualizować interfejs użytkownika, można użyć wątku Display.asyncExec lub wątku Display.syncExec, aby uruchomić kod modyfikujący interfejs użytkownika.
W przypadku, gdy operacja musi być w całości wykonana w wątku interfejsu użytkownika, należy użyć metody IProgressService#runInUI. Wyświetla ona okno postępu i przekazuje sterowanie użytkownikowi także wtedy, gdy operacja zostanie zablokowana.
progressService.runInUI( PlatformUI.getWorkbench().getProgressService(), new IRunnableWithProgress() { public void run(IProgressMonitor monitor) { //wykonanie pracy związanej z interfejsem użytkownika } }, Platform.getWorkspace().getRoot());
Trzeci parametr może mieć wartość NULL lub może być regułą planowania dla operacji. W takiej sytuacji podaje się katalog główny obszaru roboczego, co blokuje obszar roboczy na czas działania tej operacji interfejsu użytkownika.
W usłudze postępu można także zarejestrować ikonę dla rodziny zadań, dzięki czemu w widoku postępu ikona ta będzie wyświetlana obok wykonywanego zadania. Oto przykład powiązania rodziny zadań automatycznego budowania z ikoną:
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);
Interfejs IWorkbenchSiteProgressService zawiera funkcje API na potrzeby planowania zadań, zmieniające wygląd środowiska roboczego podczas wykonywania zadania. Jeśli moduł dodatkowy uruchamia w tle operacje wpływające na stan danej części, można zaplanować zadanie przy jej użyciu, dzięki czemu użytkownik będzie informowany o tym, że część jest zajęta. Oto przykład:
IWorkbenchSiteProgressService siteService = (IWorkbenchSiteProgressService)view.getSite().getAdapter(IWorkbenchSiteProgressService.class); siteService.schedule(job, 0 /* teraz */, true /* wewnątrz części użyj kursora częściowej zajętości */);
Środowisko robocze definiuje właściwości postępu dla zadań przy użyciu interfejsu IProgressConstants . Służą one do sterowania sposobem wyświetlania informacji o zadaniu w widoku postępu. Pozwalają one skonfigurować widok postępu w taki sposób, aby zachowywał (IProgressConstants#KEEP_PROPERTY) zadanie w widoku po jego zakończeniu lub żeby przechowywał zadania w widoku pojedynczo (IProgressConstants#KEEPONE_PROPERTY). Z zadaniem można także powiązać akcję (IProgressConstants#ACTION_PROPERTY). Gdy z zadaniem jest powiązana akcja, w widoku postępu wyświetlany jest odsyłacz hipertekstowy, który służy do uruchomienia akcji. Można także dowiedzieć się, czy zadanie użytkownika jest w danej chwili wyświetlane w oknie dialogowym postępu (IProgressConstants#PROPERTY_IN_DIALOG). Gdy akcja jest dostępna, z prawej strony u dołu w wierszu statusu wyświetlana jest wskazówka. Omawiane właściwości zostały użyte w poniższym przykładzie:
Job job = new Job("Do Work") { public IStatus run(IProgressMonitor monitor) { // wykonywania zadania // zakończone zadanie zostaje w widoku postępu tylko, jeśli nie było wyświetlane w oknie dialogowym postępu 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() { // wyświetla wyniki } }; job.setProperty(IProgressConstants.ACTION_PROPERTY, gotoAction); job.setUser(true); job.schedule();
O ile to możliwe, długotrwałe operacje powinny być wykonywane poza wątkiem interfejsu użytkownika. Nie jest to jednak możliwe, gdy celem operacji jest zaktualizowanie interfejsu użytkownika. W sekcji Zagadnienia dotyczące wątków SWT objaśniono, w jaki sposób można to zrobić przy użyciu widgetu Display z pakietu SWT. Środowisko robocze definiuje specjalne zadanie, UIJob, którego metoda uruchamiania działa wewnątrz wątku asyncExec pakietu SWT. Podklasy klasy UIJob powinny implementować metodę runInUIThread zamiast metody run.
Klasa WorkbenchJob rozszerza klasę UIJob w taki sposób, że zadanie może zostać zaplanowane lub uruchomione tylko wtedy, gdy działa środowisko robocze. Jak zawsze należy unikać nadmiernego obciążenia wątku interfejsu użytkownika, ponieważ interfejs użytkownika nie będzie odświeżany podczas trwania zadania UIJob.