Threads GUI über Hintergrund-Thread aktualisieren

renwal

Aktives Mitglied
Hallo!

Ich hab mal eine Frage zu folgenden Problem: Ich hab ein GUI, auf dem man eine Art Quiz machen kann. Dazu muss man zuerst ein paar Dinge einstellen, dann wird eine Liste mit Fragen generiert und das Quiz startet. Jetzt kann der Benutzer die Frage beantworten und auf OK klicken. Dann soll die nächste Frage aus dem Fragen-Array in das GUI geladen werden.

Den Weg, die Frageliste und einen Zähler global in der Klasse zu definieren und dann beim Klick auf den OK-Button immer eins weiter zu zählen, wollte ich vermeiden. Dann habe ich ja nur unnötige Objekte, wenn das Quiz gar nicht läuft. Da das Programm noch einiges mehr kann, summiert sich das irgendwann.

Stattdessen wollte ich einen Thread erstellen, der die Liste mit Fragen aufnimmt und sich so lange schlafen legt, bis der OK-Button angeklickt wird, die GUI-Aktualisierung ausführt und sich wieder schlafen legt. Mein erster Versuch war der mit
Code:
wait()
und
Code:
notify()
, das habe ich aber bald wieder aufgegeben und es mit
Code:
ReentrantLock
und
Code:
Condition
versucht. Da jetzt aber der Hintergrund-Thread in einer anderen Klasse liegt als das GUI kann ich nicht auf das Condition-Objekt zugreifen, ohne es
Code:
public static
zu machen. Da man aber ja keine Instanzen von außen modifizieren soll, bliebe nur der Weg über einen setter, dessen Aufruf von außen den wartenden Thread dann doch aber mit einer InterruptedException abwürgen würde, bevor er
Code:
condition.signal()
ausführen kann, oder?

Kann mir da jemand einen Lösungsansatz geben?
 
Also wenn du eine Liste mit Fragen hast, welche nacheinander gestellt werden sollen, wo sind denn da bitte die unnötigen Objekte????:L
Ich glaube es ist unnötig, sich solche Feldversuche anzutun, wie du es da versuchst.

Was machst du denn da so unglaubliches mit deinem Programm, dass es nicht mal eine Liste mit Fragen halten darf?
 
Stattdessen wollte ich einen Thread erstellen, der die Liste mit Fragen aufnimmt und sich so lange schlafen legt, bis der OK-Button angeklickt wird, die GUI-Aktualisierung ausführt und sich wieder schlafen legt.

Hallo,

ich versteh nicht so richtig, was dann der Sinn des seperaten Threads ist. Wenn er erst in Aktion tritt, wenn der Button geklickt wird, muss der Benutzer ja sowieso warten, bis die Darstellung aktualisiert ist, um weitermachen zu können. - Also könnte man das direkt synchron machen. Wenn es dir in erster Linie darum geht, die Darstellungslogik von der Fragensammlung zu trennen, würde ich das vielleicht so in der Art machen:


(Beim Button klick wird loadNextQuestion() aufgerufen)

Java:
public class GUITest {

	QuestionsKlasse questionsKlasse;
	
	
	public void setDisplayedQuestion(final String question)
	{
		SwingUtilities.invokeLater(new Runnable() {
			
			@Override
			public void run() {
				this.questionTextField.setText(question);
				
			}
		});
	}
	
	public void loadNextQuestion()
	{
		questionsKlasse.loadNextQuestion();
	}

Java:
public class QuestionsKlasse {

	GUITest gui;
	List<String> questions;
	
	public void loadNextQuestion() {
		
		String currentQuestion = questions.remove(0);
		gui.setDisplayedQuestion(currentQuestion);
	}

}

Ansonsten hilft dir vielleicht das MVC Modell
 
Achso, vielleicht war deine Intention bei dem seperaten Thread, dass die GUI nicht hängt, wenn das laden länger dauert.
Dann könntest du beim Aufruf einen Worker Thread starten:


Java:
	public void loadNextQuestion()
	{
		Thread worker = new Thread(new Runnable() {
			
			@Override
			public void run() {
				questionsKlasse.loadNextQuestion();
				
			}
		});
		worker.start();
	}

Oder über SwingWorker, Thread Pool
 
Zuletzt bearbeitet:
Irgendwie gefällt mir dein ursprünlicher Ansatz jetzt auch, da man so nicht immer neue Threads starten muss.
Würde das dann in etwa so machen:


Java:
public class QuestionsLoaderJob implements Runnable 
{

	GUITest gui;
	List<String> questions;
	boolean goOn;

	@Override
	public void run() 
	{
		while (goOn) 
		{
			String currentQuestion = questions.remove(0);
			gui.setDisplayedQuestion(currentQuestion);
			synchronized (this) 
			{
				try 
				{
					wait();
				} 
				catch (InterruptedException e)
				{
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

	public void loadNextQuestion() 
	{
		synchronized (this) 
		{
			notify();
		}
	}
}

Alle Beispiele sind nicht lauffähig und stark vereinfacht, um die Sache auf den Punkt zu bringen.

Poste doch mal, was du bis jetzt hast und was nicht funktioniert.
 
Also wenn du eine Liste mit Fragen hast, welche nacheinander gestellt werden sollen, wo sind denn da bitte die unnötigen Objekte????:L
Ich glaube es ist unnötig, sich solche Feldversuche anzutun, wie du es da versuchst.

Was machst du denn da so unglaubliches mit deinem Programm, dass es nicht mal eine Liste mit Fragen halten darf?

das ist die richtige Antwort im Grunde.... Threads scheinen hier ein wenig sehr weit hergeholt.
 
Ihr habt wohl recht. Ich wollte halt einfach nicht Unmengen an Objekten erzeugen, die dann unbenutzt "rumliegen" wenn sich das Programm in einem anderen Modus befindet. Da dachte ich halt, wenn ich am Ende den Thread beende, dann bin ich auch das Objekt los. Wenn ich die Liste in der Hauptklasse definiere, geht das nicht, ich kann ja nicht die Hauptklasse beenden. Das Programm zieht halt mit jedem Objekt mehr auch mehr Speicher. Da das ganze Projekt recht aufwändig ist, wollte ich eben Speicher sparen.

DougUndPizza hat gesagt.:
Achso, vielleicht war deine Intention bei dem seperaten Thread, dass die GUI nicht hängt, wenn das laden länger dauert.
Dann könntest du beim Aufruf einen Worker Thread starten:

Nein, war es nicht. Das habe ich schon vorher über einen Worker Thread gemacht, so wie du es geschrieben hast.
 

Zurück
Oben