Laufend aktualisierte GUI-Ausgabe statt Konsole

Joghurt

Grünschnabel
Hallo,

ich bastel gerade meine GUI (ich benutze SWT) zusammen. Dort soll während einer langen Berechnung immer eine aktualisierte Statistik mitlaufen, also z.B. ein Zähler, der mitläuft und in einem Textfeld aktualisiert wird usw.

Idealerweise auch mit Graphen, die den Verlauf anzeigen, einem Zähler, der die verstrichene Zeit misst usw.

Sowas hab ich aber noch nie gemacht. Meine Fragen:

- Geht sowas überhaupt mit SWT?
- Was für Klassen nimmt man am besten dafür? Die aus dem org.eclipse.swt.graphics Paket?

Der Kontrollfluss ist ungefähr so:

- Programm startet
- Welt wird erschaffen
- Gui wird erschaffen
- Per Knopfdruck fängt die Welt an wilde Sachen zu machen, die ich auf der Konsole ausgebe

Wie kann ich das jetzt in der GUI ausgeben? Die Welt weiss ja schließlich nichts von der GUI? Muss man sowas generell mit Threads lösen?

Über Tipps würde ich mich sehr freuen.

Gruß,

Joghurt
 
Nein, eigentlich eher eine Verlaufskurve wie z.B. bei Börsenkursen. Geht mal höher, mal niedriger. Und halt die Sache wie ich von berechnenden Objekt aus die GUI aktualisiere.

Ich hab dem Objekt jetzt als Parameter das GUI Objekt mitgegeben und dann soll es jetzt immer eine Methode des GUI Objekts aufrufen, damit dieses sich ändert. Macht man das so?
 
Original geschrieben von Joghurt
Ich hab dem Objekt jetzt als Parameter das GUI Objekt mitgegeben und dann soll es jetzt immer eine Methode des GUI Objekts aufrufen, damit dieses sich ändert. Macht man das so?

Kann man machen. Flexibler und für größere Projekte geeigneter ist das Listener-Konzept. Zumal wenn die GUI nicht nur aus einem Fenster/Frame besteht und sich Änderungen in der Datenklasse an verschiedenen Stellen auswirken sollen, sprich eine Aktualisierung der Anzeige erforderlich ist.
 
Erstmal vielen Dank für Eure Hilfe! ;-)

Stimmt. Das hört sich logisch an. Aktualisiert werden sollen zwei Text-Objekte und dann halt die Sache mit der mitlaufenden Kurve für die Statistik (aber das ist erstmal nur Zugabe).

Wer kriegt jetzt die Listener? Jedes der beiden Text-Objekte? Eines wird laufend aktualisiert (Zähler), das andere nur von Zeit zu Zeit (aktuell bestes Ergebnis). Oder kriegt das Fenster, in dem sich beide befinden, den Listener?

Die berechnungen laufen in einer Methode der Art

welt.berechne(AusgabeFenster ausgabeFenster){
for (int zaehler=1 ; zaehler<=1000000 ; zaehler++) {
...
[zaehlerTextfeld in der GUI aktualisieren]
[unter best. Umständen ausgabeTextfeld aktualisieren]
}
}

Da muss ich dann Event-Ereignisse erschaffen und an die Text-Objekte übergeben?
 
Zuletzt bearbeitet:
Original geschrieben von Joghurt
Stimmt. Das hört sich logisch an. Aktualisiert werden sollen zwei Text-Objekte und dann halt die Sache mit der mitlaufenden Kurve für die Statistik (aber das ist erstmal nur Zugabe).

Wer kriegt jetzt die Listener? Jedes der beiden Text-Objekte? Eines wird laufend aktualisiert (Zähler), das andere nur von Zeit zu Zeit (aktuell bestes Ergebnis). Oder kriegt das Fenster, in dem sich beide befinden, den Listener?

Die berechnungen laufen in einer Methode der Art

welt.berechne(AusgabeFenster ausgabeFenster){
for (int zaehler=1 ; zaehler<=1000000 ; zaehler++) {
...
[zaehlerTextfeld in der GUI aktualisieren]
[unter best. Umständen ausgabeTextfeld aktualisieren]
}
}

Da muss ich dann Ereignisse erschaffen und an die Objekte übergeben?

Deine beiden Text-Objekte deines JFrame (?) sollen ja reagieren. Also registrierst Du das Frame als Listener bei der Datenklasse. Im einzelnen sieht das z.B. so aus:

Datenklasse:
- In der Datenklasse legst Du eine ArrayList an, die die Listener beinhaltet, z.B. alListener
- In der Datenklasse implementierst Du eine zugehörige addViewListener(ViewListener l)-Methode und notifyViewListeners()
- In der addViewListener(...) fügst Du den übergebenen ViewListener einfach nur der ArrayList alListener hinzu.
- In der notifyViewListeners() iterierst Du über die ArrayList und lässt jeden einzelnen ViewListener darin die Interface-Methode ausführen (1)
- An den Stellen, an denen sich Daten ändern oder aus sonstigen Gründen die Listener benachrichtigt/aktualisiert werden sollen, rufst Du einfach notifyViewListeners() auf.

(1) Interface
- Leg eine Klasse als Interface an, z.B. ViewListener
- Darin definierst Du Deine Interface-Methode, z.B. fireViewChanged

(2) GUI/Frame:
- Implementiere das Interface ViewListener
- Implementiere die Methode fireViewChanged (MUSS!)
- In der Methode fireViewChanged rufst Du die notwendigen Aktualisierungen der GUI/des Frames auf
- Nun muss nur noch GUI/Frame als Listener der Datenklasse hinzugefügt werden. HIer eignet sich üblicherweise eine Instanz der Datenklasse als Singleton anzulegen und z.B. so aus der GUI hinzuzufügen: MyDataClass.getInstance().addViewListener( this );

Ich hoffe, das ist einigermaßen verständlich, aber so funktionieren Listener. Falls Du noch einen anderen Dialog oder einen anderen Frame aktualisieren möchtest, gehst Du einfach wieder wie in (2) vor, das ist schon alles.

(Ob man das als Tutorial nehmen kann? ;) Vllt. mit einem einfachen Beispielcode?)

Ah noch was: Unter Umständen ist die Performance nicht so prickelnd, in der Schleife bis 1000000 jedes mal die GUI zu aktualisieren, wirste aber sehen.
 
Wow! Vielen Dank für die ausführliche Antwort. Ich werd mir das mal anschauen und versuchen, es zu verstehen. Evtl. aktualisiere ich die GUI dann eben nur jeden 50. oder 100. Durchlauf.

Ich benutze übrigens keinen JFrame, sondern hab mir sowas zusammengebastelt:

public class Fenster {
protected Shell shell = new Shell();
protected Display display = null;
}

Alle vorkommenden Fenster sind dann Erweiterungen davon, z.B.

public class guiHauptfenster extends Fenster() {
...
}

mit GridLayout, Group, Button und Text-Objekten. Ich weiss jetzt nicht, ob man das so macht, aber es funktioniert...
 
Soweit klappt alles ganz gut. Nur einen Haken hat die Sache:

die Methode fireZaehlerAktualisieren() wird im Daten-Objekt der Weltklasse (mittlerweile Singleton) korrekt aufgerufen. Das hab ich per Ausgabe überprüft. Allerdings wird die GUI nur 1x geändert bzw. die Änderung sichtbar und zwar genau am Ende des Programms.

final Label zaehlerText = new Label(gruppeZaehler, SWT.WRAP);

public void setZaehler(String string) {
zaehlerText.setText(string);
zaehlerText.pack();
}

public void fireZaehlerAktualisieren(){
int zufallszahl = MatheFunktionen.zufallsInt(1,100);
String string = ""+zufallszahl;
this.setZaehler(string);
System.out.println("fireZaehlerAktualisieren aufgerufen: "+ zufallszahl);
}
 
Scheint wohl an der schlecht realisierten VM von Mac OS X zu liegen. Auf meinem Windows Rechner läuft es. Echt zum kotzen, wie stiefmütterlich Java für alle nicht Win-Systeme behandelt wird. War unter Linux ähnlich träge...
 

Neue Beiträge

Zurück