tutorials.de Buch-Aktion 05/2012
ERLEDIGT
NEIN
ANTWORTEN
12
ZUGRIFFE
1346
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    Joghurt Joghurt ist offline Mitglied
    Registriert seit
    Sep 2004
    Beiträge
    12
    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
     

  2. #2
    Rick Dangerous Rick Dangerous ist offline Mitglied Silber
    Registriert seit
    Aug 2004
    Beiträge
    96
    Du meinst also eine ProgresBar, die den Fortschritt einer Berechnung anzeigt?

    http://java.sun.com/docs/books/tutor.../progress.html
    google-suche
     

  3. #3
    Joghurt Joghurt ist offline Mitglied
    Registriert seit
    Sep 2004
    Beiträge
    12
    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?
     

  4. #4
    Registriert seit
    Apr 2004
    Ort
    Ruhrgebiet
    Beiträge
    1.582
    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.
     

  5. #5
    Joghurt Joghurt ist offline Mitglied
    Registriert seit
    Sep 2004
    Beiträge
    12
    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?
    Geändert von Joghurt (22.09.04 um 11:15 Uhr)
     

  6. #6
    Registriert seit
    Apr 2004
    Ort
    Ruhrgebiet
    Beiträge
    1.582
    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.
     

  7. #7
    Joghurt Joghurt ist offline Mitglied
    Registriert seit
    Sep 2004
    Beiträge
    12
    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...
     

  8. #8
    Registriert seit
    Apr 2004
    Ort
    Ruhrgebiet
    Beiträge
    1.582
    Kann man sicher auch machen, für das Listener-Konzept ist das allerdings egal.
     

  9. #9
    Joghurt Joghurt ist offline Mitglied
    Registriert seit
    Sep 2004
    Beiträge
    12
    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);
    }
     

  10. #10
    Joghurt Joghurt ist offline Mitglied
    Registriert seit
    Sep 2004
    Beiträge
    12
    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...
     

  11. #11
    Registriert seit
    Apr 2004
    Ort
    Ruhrgebiet
    Beiträge
    1.582
    Original geschrieben von Joghurt
    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.

    Code :
    1
    2
    3
    4
    5
    6
    
        public void fireZaehlerAktualisieren(){
            int zufallszahl = MatheFunktionen.zufallsInt(1,100);
            String string = ""+zufallszahl;
            this.setZaehler(string);
            System.out.println("fireZaehlerAktualisieren aufgerufen: "+ zufallszahl);
        }
    Bei Problemen mit der Aktualisierung hilft oftmals ein repaint().
     

  12. #12
    Avatar von takidoso
    takidoso takidoso ist offline Mitglied Brillant
    Registriert seit
    Aug 2004
    Ort
    Kömigstein
    Beiträge
    911
    Zitat Zitat von Joghurt
    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.
    Halli hallo,
    das Problem, dass das GUI sich nicht aktualisiert liegt nicht selten daran, das man seine Berechnungen in den Thread gelegt hat, in dem das System seine GUI-Anforderungen (Events) verarbeitet. Ich weiß nicht wie es in Eclipse genannt wird und welche Routinen man da verwenden muß, aber in Swing gibt es da 2 Methoden

    1) SwingUtilities.invokeLater(Runable);
    2) SwingUtilities.invokeAndWait(Runable);

    In anderen Worten, man lässt seine Berechnungen, so sie lange dauern, in einen extra Thread ablaufen und ruft daraus eine der obigen Routinen auf um damit das GUI zu verändern.
    Dem zufolge sollten die Änderungen als Runable definiert werden.

    Du mußt mal, falls Eclipse ähnliches bereithält, natürlich die equivalenten Routinen suchen/finden/anwenden.

    In der Hoffnung der Tip hilft,

    Takidoso
     

  13. #13
    Registriert seit
    Jun 2002
    Ort
    Saarbrücken (Saarland)
    Beiträge
    9.886
    Blog-Einträge
    29
    Hallo!

    Schau dir doch mal die Methoden:
    syncExec(Runnable runnable)
    Causes the run() method of the runnable to be invoked by the user-interface thread at the next reasonable opportunity.

    und

    asyncExec(Runnable runnable)
    Causes the run() method of the runnable to be invoked by the user-interface thread at the next reasonable opportunity.

    der Klasse: org.eclipse.swt.widgets.Display

    an.

    Gruß Tom
     
    Java rocks!
    How to become a good Java Programmer?
    Does IT in Java and .Net
    The only valid measurement of code quality: WTFs / minute
    Blog
    Xing
    Twitter

Ähnliche Themen

  1. Antworten: 15
    Letzter Beitrag: 16.08.09, 22:31
  2. Ausgabe in cmd-Fenster statt Konsole
    Von Ashaman im Forum Java Grundlagen
    Antworten: 5
    Letzter Beitrag: 01.07.08, 15:03
  3. Textarea statt Konsole!
    Von Ramix im Forum Java
    Antworten: 3
    Letzter Beitrag: 20.12.07, 21:17
  4. Hilfe! û statt - in der Konsole!
    Von athlon im Forum Microsoft Windows
    Antworten: 2
    Letzter Beitrag: 27.09.05, 19:53
  5. Ausgaben von SELECT in Datei statt auf Konsole
    Von MichiM im Forum Relationale Datenbanksysteme
    Antworten: 3
    Letzter Beitrag: 18.08.04, 18:07