[Swing] czekanie na wystąpienie zdarzenia

0

Chcę nadzorować aplikację w Swingu z wątku głównego. Mam zamiar wpływać z wątku głównego na okienko
Swingowe, następnie czekać aż użytkownik je wypełni oraz zatwierdzi przyciskiem, a kiedy to nastąpi znowu ingerować w nie z wątku głównego. Na razie osiągnąłem ten efekt w ten sposób:

public void testTestingDialog(){
        ...
        blocker = new SwingBlocker();
	dialog.addActionListener(blocker);
        ...

	String answer;
	dialog.setQuery("Kapelusz");
	waitForEvent();
	answer = dialog.getAnswer();
	System.out.println(answer);
	dialog.setQuery("Marynarka");
	waitForEvent();
	answer = dialog.getAnswer();
	System.out.println(answer);
}

private void waitForEvent(){
	blocked = true;
	while(blocked){
		try{Thread.sleep(100);}catch(InterruptedException e){}
	}
}

private static class SwingBlocker implements ActionListener{
@Override public void actionPerformed(ActionEvent arg0) {
		blocked = false;
	}
}

Jednak nie wiem, czy jest to dobry sposób na ogsługę wątków w Swingu. Czy da się to zrobić w jakiś lepszy lub bardziej elegancki sposób?

0

Najgorzej jak się da. Po pierwsze nie blokujesz wątku głównego ponieważ Swing i tak działa w osobnym wątku. Jedyne co możesz tu osiągnąć to wysypujące się na potęgę InterruptedExeption.

Jeżeli chcesz aby coś zostało wykonane w wyniku naciśnięcia przycisku to zamiast zmieniać flagę w ActionListenerze przenieś tam wywołanie kodu.
Moja propozycja:


public void testTestingDialog(){
        ...
        blocker = new SwingBlocker();
        dialog.addActionListener(blocker);
        ...

        dialog.setQuery("Kapelusz");
        waitForEvent();
        answer = dialog.getAnswer();
        System.out.println(answer);
        dialog.setQuery("Marynarka");
        
}

private static class SwingBlocker implements ActionListener{
@Override public void actionPerformed(ActionEvent arg0) {
            System.out.println(dialog.getAnswer());
        }
}

Wykonanie nastepuje po nacisnięciu przycisku.

0

No tak, Koziołek, ale teraz to mi pokazałeś zwykłego ActionListenera i zwyczajne przetwarzanie oparte na zdarzeniach :(. A ja właśnie po to tak kombinuję, żeby uniknąć takiego podejścia i móc obsługiwać w pojedynczym bloku kodu (w 1 metodzie) szereg następujących po sobie akcji użytkownika, a nie przenosić logikę programu do listenerów.

Po pierwsze nie blokujesz wątku głównego ponieważ Swing i tak działa w osobnym wątku.

Tego fragmentu nie rozumiem, wydawało mi się, że ta metoda:

private void waitForEvent(){
        blocked = true;
        while(blocked){
                try{Thread.sleep(100);}catch(InterruptedException e){}
        }
}

właśnie blokuje wątek główny.

0

Doom77 - Swing nie jest wielowątkowy, a ty najwyraźniej chcesz wywoływać metody Swinga wprost z main(), która to metoda jest popychana przez zupełnie inny wątek (może nawet inny procesor). A to oznacza, że nawet jeżeli coś wykombinujesz, to będziesz musiał wszystkie wywołania opakowywać przez invokeLater() lub invokeAndWait(). W efekcie Twój kod będzie wyglądał jak produkcja szalonego elektryka.
Nie mówię, że to niemożliwe, ale taka koncepcja jest kompletnie nie po drodze z asynchronicznym Swingiem czy nawet równie asynchronicznym SWT. Ratować Cię może jedynie samodzielne niskopoziomowe rysowanie grafiki pełnoekranowej wprost z main, ale wtedy o funkcjach Swinga jako rozwiązaniu raczej zapomnij.

A mógłbyś zdradzić, co Cię popchnęło do takiej koncepcji, żeby za pomocą wątku metody main() chcieć kontrolować wątek Swinga?

A poza tym jak chcesz z metody main() odczytywać wciśnięcia klawiszy czy ruchy myszy? Przecież sprowadza się to do powielenia GUI, co jest wyważaniem otwartych drzwi. Najważniejszą zaleta Swinga jest moim zdaniem właśnie bardzo elegancja obsługa zdarzeń (listenery). Grafikę, można sobie samemu skombinować - obsługę urządzeń już nie tak łatwo.

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