W metodzie doInBackground
obiektu SwingWorker<RESULT,PROGRESS>
zazwyczaj jest jakaś pętla. W niej co jedną iterację wywołujesz metodę publish(PROGRESS... wartościPośrednie)
z jednym lub kilkoma argumentami, które podają kolejne stany postępu. Typem PROGRESS
jest jakiś typ porządkowy - zazwyczaj obiektowy int
, czyli Integer
, a zakresem wartości [0,100], co dobrze obrazuje procentowy postęp zadania. U Ciebie zakresem może być [1,250].
Wywołanie publish
z argumentem konkretnej wartości typu PROGRESS powoduje to, że niedługo potem* pojawia się w Swingu zdarzenie, które skutkuje wywołaniem z wątku EDT (czyli tym na którym są obsługiwane zdarzenia GUI kontrolek Swinga) metody process
tego obiektu SwingWorkera, u którego nastąpiło wywołanie publish
. Dzięki temu, że metodą tą porusza wątek EDT można bezpośrednio z niego ustawiać wszystkie kontrolki - na przykład różne JLabele za pomocą ich setText
, które obrazują stan licznika/postępu, i to bez pośrednictwa metody invokeLater
.
Normalnie w publish jest tylko jedna bieżąca wartość pośrednia, ale może się zdarzyć, że wywołanie w wątku EDT tak się opóźni, że w tym czasie wywołają się dwie lub więcej metody publish
. Dlatego w process
dostajesz listę kolejnych wartości, a nie samą ostatnią wartość (można brać z listy tylko ostatnią z wartości dla zobrazowania postępu).
Ostatecznie, kiedy zakończy się pętla w doInBackground
, a zwykle i cała ta metoda, wtedy w podobnym trybie wywoływana jest z wątku EDT metoda done
, która służy zazwyczaj do posprzątania i ewentualnie ostatecznego wyświetlenia wyników na jakiejś kontrolce.
Formalnie wartością wywołania konstruktora SwingWorkera jest coś takiego jak Future<RESULT> (SwingWorker implementuje taki interfejs). Sam typ Future to taka śmieszna wartość, która "opakowuje" dane dostępne w przyszłości. Wywołanie jej metody get zanim dane będą dostępne spowoduje oczekiwanie aż wykona się cały doInBackground
, który te dane uzyska - spowoduje to oczywiście przyblokowanie wykonywania wątku, więc nie wolno tego wywoływać z wątku EDT (na przykład z obsługi jakiegoś listenera). Dopiero kiedy zakończy się praca, czyli gdy metoda SwingWorker.isDone
będzie zwracać true można wywołać get
bez obawy o przestoje - dane będące wynikiem zostaną udostępnione od razu (wtedy będzie już ta "przyszłość").
Można też pominąć SwingWorkera i robić wszystko na osobnym wątku - takim jaki stworzyłeś. Ale wtedy musisz sobie sam zorganizować aktualizację licznika i dostęp do niego z Twoich kontrolek. Robi się to zwykle przez zrobienie licznika polem obiektu z modyfikatorem volatile (może być prywatne z dostępem przez gettera), a z pętli w której się kręci musisz sam wywoływać sobie za pomocą invokeLater
jakieś polecenie setLabel z nową wartością a następnie kontrolki te aktualizować przez swingową metodę validate
i na koniec repaint
aby kontrolki przerysowały się z nową aktualną zawartością.
Właściwie SwingWorker
w tak prostych przypadkach nie daje żadnej istotnej przewagi poza standaryzacją wykonywania takich zadań. Jednak ponieważ kolejne zadania mogą być coraz bardziej skomplikowane, to warto nauczyć się jak używać tej klasy.
Co do zasady różnica między wyświetlaniem w konsoli, a pracą z oknami polega na tym, że w konsoli to ty wyrzucasz dane na ekran/konsolę, co programujesz w jakiejś pętli. W przypadku okien Twoje programowanie sprowadza się do tego aby swoim kontrolkom dać przepis na to jak te dane na bieżąco uzyskiwać. Kontrolki są kontrolowane i odrysowywane przez system, więc aby mogły wyświetlić np. jakiś tekst, to muszą wiedzieć jak się do niego dobrać. I tu do gry wchodzi Twój kod, który wie jak te dane uzyskać. Krótko mówiąc przy tradycyjnym programowaniu ty dane pchasz do konsoli, natomiast przy programowaniu zdarzeniowym kontrolki sobie te dane same ciągną na bieżąco.
Natomiast jeżeli tak jak w tym wypadku ty musisz te dane aktywnie zmieniać (czyli tradycyjnie), to oprócz aktualizowania tych danych dla kontrolek musisz te kontrolki dodatkowo informować, że coś się w tych danych zmieniło. Bez tej informacji kontrolki mogą "uważać", że żadne dane się nie zmieniły i wciąż będą wyświetlać to co wcześniej.
Tak mniej więcej wygląda Twój problem i takie jest rozwiązanie.
-
- nad tym odstępem czasu nie masz żadnej kontroli poza zapewnieniem, że będzie to tak szybko jak to możliwe.