Wątek ze statusem postępu (odświeżanie stanu)

0

Od jakiegoś czasu piszę pewien program (Frameworka) do testowania algorytmów wyszukiwania wzorca w tekście. Chciałem w nim umieścić etykietę JLabel informującą na bieżąco o postępie wykonywanych testów.

Najpierw, próbowałem to zrobić bez dodatkowych wątków, z użyciem repaint(). To nie działało więc stworzyłem taką klasę implementującą interfejs Runnable:


class ProgressStatusThread implements Runnable
{
	private JLabel status;
	private JPanel jpnl;
	Thread thrd;
	
	ProgressStatusThread (String name, JPanel pnl)
	{
		thrd = new Thread(this, name);
		jpnl = pnl;
		
		status = new JLabel("Postęp: ");
		status.setBounds(670, 220, 70, 25);
		jpnl.add(status);
	}
	
	public void setStatus(String str)
	{
		status.setText(str);
	}
	
	public void run ()
	{
		try {
			status.repaint();
			Thread.sleep(250);
		}
		catch (InterruptedException exc)
		{
		}
	}
	
}

Następnie wątek jest tworzony i jego działanie testowane w jednej z metod, wywoływaną przez inną z metod...itd. koniec końców działającej w metodzie main. Fragment kodu:


int partlyTest (String txt, String pat, MyTimer myTimer, String name)
	{
		int i, amount = 200;
		long start, stop;
		myTimer.timer = (long)0;
		long time = 0;
		
		ProgressStatusThread psT = new ProgressStatusThread("progress status", jpnlDetailedTests);
		Thread thrd1 = new Thread(psT);
		
		thrd1.start();
		
		
		if(name.equals("n")) //Naiwny
		{
			for (i=0; i<100; i++)
			{ 
				psT.setStatus("Postęp: " + i); //
				start = System.currentTimeMillis();
				
				for(int j=0; j<amount; j++)
					searchObj.nSearch(txt, pat);
				
				stop = System.currentTimeMillis();
				
				time +=(stop-start);
			}
			
			time /= i;
		}
...

Niestety etykieta nie aktualizuje się na bieżąco, tylko po wykonaniu testów wyświetla 99.
Nie wiem co jest nie tak. Może wcale nie jest potrzebny nowy wątek tylko nie rozumiem jak działa repaint(), ale z tego co czytałem to właśnie aktualizuje zawartość komponentu dla której jest wywoływana poprzez wywołanie paint().
Będę wdzięczny za pomoc.

0

Spróbuj pierwszego sposobu, ale zaraz po repaint() dodawaj validate() i napisz, czy jest jakaś różnica.

0

Spróbowałem jeszcze raz z pierwszym sposobem - bez wątków, poprzez wywołanie repaint() i validate(), ale nie pomogło. Nie wyskakuje też nic w związku z walidacją, zresztą w Eclipse w opisie metody jest informacja, że validate() sprawdza kontener i jego wszystkie podkomponenty, a JLabel nie jest przecież kontenerem.

Tak czy inaczej, kod nie działa tak jak powinien i wygląda w ten sposób:


int partlyTest (String txt, String pat, MyTimer myTimer, String name)
	{
		int i, amount = 200;
		long start, stop;
		myTimer.timer = (long)0;
		long time = 0;
		
		
		if(name.equals("n")) //Naiwny
		{
			for (i=0; i<100; i++)
			{ 
				jlabProgress.setText("Postęp: " + i);
				jlabProgress.repaint();
				jlabProgress.validate();
				
				start = System.currentTimeMillis();
				
				for(int j=0; j<amount; j++)
					searchObj.nSearch(txt, pat);
				
				stop = System.currentTimeMillis();
				
				time +=(stop-start);
			}
			
			time /= i;
		}

0

Może prościej, prościej też w ogóle nie informować o postępie i problem z głowy. Jednak w ten sposób nie dowiem się dla czego mój kod nie działa tak jak chcę i przy najbliższej podobnej sytuacji z czymś innym niż pasek postępu znowu utknę w tym samym miejscu. Nie mniej jednak w linku, który podałeś była linijka paintString czy coś takiego więc pomyślałem, że metoda repaint() jest tylko do obiektów, które są "painted". Poczytałem w dokumentacji oracle'a i okazało się, że repaint() jest tylko dla "lightweight" components a dla innych jest metoda upadate(). Nie wiedząc czy JLabel jest "lekkim" czy "ciężkim komponentem", spróbowałem mimo wszystko z update() i zaraz po uaktualnieniu etykiety do wartości 0 wysypał mi się program. Stało się tak pewnie dla tego, że w miejscu gdzie powinien być obiekt klasy Graphics wstawiłem null, ale wyświetlenie 0 na początku świadczy o tym, że może jednak metoda update będzie działać jak nad tym chwilę przysiądę (bo na razie mam problem z odpowiednim stworzeniem obiektu Graphics).

Kod na chwilę obecną:

 
for (i=0; i<100; i++)
		{ 
			jlabProgress.setText("Postęp: " + i);
			jlabProgress.update(null);
				
			start = System.currentTimeMillis();
				
			for(int j=0; j<amount; j++)
				searchObj.nSearch(txt, pat);
				
			stop = System.currentTimeMillis();
				
			time +=(stop-start);
		}

[edit]

No cóż, moje rozwiązywanie problemu wczoraj i dzisiaj rano wyglądało następująco. Po zmianie linijki z jlabProgress.update(null); na jlabProgress.update(jlabProgress.getGraphics()); wydawało się, że już prawie działa. Tzn. zawartość etykiety niby się aktualizowała ale nie usuwając poprzednich wartości w związku z czym w miejscu gdzie powinny ładnie zmieniać się cyferki, nowe rysowały się na starych i powstawała tylko czarna plama, która na koniec po chwili "myślenia" zmieniała się na ładne 99. Myślałem, że dzieje się tak dla tego, że liczby lecą zbyt szybko w tej pętli ale nawet po dodaniu Thread.sleep(250) i próbach stworzenia osobnego wątku, działo się to samo.
Później zauważyłem, że komponenty mają metodę isLightweight(), po jej wykonaniu dowiedziałem się, że jednak JLabel jest "lightweight" więc powinno się jednak używać repaint().
Repaint jednak działało tak jak wcześniej - czyli tylko na koniec etykieta wyświetlała 99, pomijając wcześniejsze liczby. Poczytałem trochę o metodzie repaint() i wyczytałem że łączy się ona z innymi wywołaniami repaint w celu optymalizacji pracy. Czyli jeżeli wywołamy repaint() a wcześniej już jakiś komponent sam ją wywoła wówczas, zostaje wykonywane tylko pierwsze wywołanie żeby nie nadkładać pracy. Pozostało mi więc ręczne wywołane paint() chociaż wiem, że nie powinno się tego robić. Napisałem więc linijkę: jlabProgress.paint(jlabProgress.getGraphics()); i dzieje się dokładnie to samo co się działo w przypadku jlabProgress.update(jlabProgress.getGraphics()) czyli nowe liczby rysują się na starych :( . Naprawdę nie mam już na to pomysłu, nie wiem jak to naprawić, ma ktoś jakiś pomysł ?

Aktualny kod:

if(name.equals("n")) //Naiwny
		{	
			for (i=0; i<100; i++)
			{ 
				try
				{
					Thread.sleep(50);
				}
				catch (InterruptedException exc)
				{
				}
				jlabProgress.setText("Postęp: " + i);
				jlabProgress.paint(jlabProgress.getGraphics());
				
				start = System.currentTimeMillis();
				
				for(int j=0; j<amount; j++)
					searchObj.nSearch(txt, pat);
				
				stop = System.currentTimeMillis();
				
				time +=(stop-start);
			}
			
			time /= i;
		}

1 użytkowników online, w tym zalogowanych: 0, gości: 1