JLearner: JTextBox Hintergrund aktualisieren

Hi

Habe ne Methode die sieht so aus:

public void runAnimation() {
    for(int i=1;i<=255;i++) {
 txtUserNumber.setBackground(new Color(i,50,50));
 try { Thread.sleep(500); } catch(InterruptedException e) {}
 repaint();
    }
}

Sie soll im Abstand von 500ms den Background der JTextBox(txtUserNumber) mit einer anderen Farbe zeichnen. Das funktioniert aber nicht, dh. die Farbe des Textfeldes wird nicht neu gezeichnet! Der Timer habe ich eingebaut damit das ganze ein bisschen animiert aussieht...

Warum klappts nicht?

JLearner

  1. Hallo,

    public void runAnimation() {
        for(int i=1;i<=255;i++) {
    txtUserNumber.setBackground(new Color(i,50,50));
    try { Thread.sleep(500); } catch(InterruptedException e) {}
    repaint();
        }
    }

    Warum klappts nicht?

    Ich spekuliere einfach mal:

    Du rufst die obenstehende Methode als Reaktion auf ein Event auf, also
    beispielweise als Reaktion auf einen Buttonklick oder eine sonstige
    User-Aktion. Und du erzeugst auch keinen neuen Thread. Richtig?

    Gruß
    Slyh

    1. Hallo Slyh

      So ist's. Aber was heisst das nun?

      Gruss

      1. Hallo,

        na super. Jetzt habe ich gerade eine längliche Antwort auf dein Posting
        geschrieben, und dann schließe ich aus Versehen -- warum auch immer --
        das Browser-Fenster. *grummel*

        Also nochmal.

        So ist's. Aber was heisst das nun?

        Kurz erklärt:
        Alle Events werden im EventDispatch-Thread verarbeitet. Dies gilt auch
        für "Zeichne mal neu"-Events (aka Repaint). Es wird immer ein Event
        nach dem anderen abgearbeitet. D.h. daß die Methode, die auf einen Event
        reagiert, zuerst wieder zurückkehren muß, bevor der nächste Event in der
        Event-Queue abgearbeitet wird. In deinem Fall muß also zuerst die Methode
        actionPerformed(), die ja wiederum runAnimation() aufgerufen hat,
        zurückkehren, bevor der nächste Event ausgeführt werden kann, der
        möglicherweise das Neuzeichenen der Komponente(n) anstößt.

        In deinem Java-Buch ist das mit der Event-Queue und dem EventDispatch-
        Thread vermutlich sehr viel besser erklärt.

        Die Lösung deines Problems ist erstmal einfach:
        Du führst deine for-Schleife in einem eigenen Thread aus, der in
        der Methode actionPerformed() erzeugt und gestartet wird. Die Methode
        actionPerformed() läuft dann weiter (beendet sich also), während
        der Thread mit der for-Schleife parallel dazu läuft und damit den
        EventDispatch-Thread nicht blockiert.

        So einfach ist es dann aber doch nicht. Komponenten dürfen nämlich
        nur innerhalb des EventDispatch-Threads verändert werden.
        Das hört sich jetzt wie ein Widerspruch an: Einerseits blockiert die
        for-Schleife den EventDispatch-Thread, und damit das Neuzeichnen
        der Komponente, andererseits muß die Änderung aber im EventDispatch-
        Thread erfolgen.
        Das ist aber nur auf den ersten Blick unlogisch. Swing ist nicht
        thread-safe. D.h. daß alle Änderungen, die eben nicht aufgrund eines
        Events (der ja im EventDispatch-Thread ausgeführt werden würde) durch-
        geführt werden sollen, von Hand in den EventDispatch-Thread "geschoben"
        werden müssen. Hierfür bietet die Klasse SwingUtilities die Methode
        invokeLater(Runnable). Diese nimmt ein Objekt der Klasse Runnable
        entgegen und fügt dieses an das Ende der EventQueue an. Sind alle
        vorherigen Events abgearbeitet, wird die run()-Methode des Objekts
        aufgerufen.

        Du mußt also in deiner For-Schleife ein Runnable-Objekt erzeugen
        (z.B. als anonyme Inner-Class), in dessen run()-Methode die eigentliche
        Änderung der Komponentenfarbe ausgeführt wird.
        (Die For-Schleife muß natürlich trotzdem innerhalb eines eigenen
        Threads laufen, da sonst nachwievor der EventDispatch-Thread blockiert
        werden würde.)

        Alle Klarheiten beseitigt? Gut. :-)

        Das Java-Buch deiner Wahl wird dir die ganze Geschichte mit dem
        EventDispatch-Thread und invokeLater erheblich besser erklären können,
        als ich das mit meinen paar Zeilen Text könnte. Lies einfach dort
        mal nach.

        Ansonsten kann ich dir noch das Vorlesungsskript zur Vorlesung
        "Benutzeroberflächen" an der FH-Karlsruhe von Holger Vogelsang
        Nahe legen. (http://www.fbi-lkt.fh-karlsruhe.de/~voho0001/Benutzeroberflachen/Vorlesung/FB08-Swing_I18N_und_Ablaufsteuerung.pdf
        ab Seite 27)
        Dort wird die ganze Sache meiner Ansicht nach sehr gut
        und kompakt beschrieben. Natürlich steht näheres auch in der Java-API-
        Doku. Vermutlich gibt es außerdem ein Java-Tutorial von Sun dazu.

        Wenn du konkrete Fragen hast, frag einfach hier nach.

        Gruß
        Slyh

        1. hallo,

          noch eine kleine, unscheinbare ergänzung in form eines links: http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html#EDT

          mit freundlichen grüßen
             dimitri rettig

      2. Hallo ihr beide!

        Danke für die Antworten! Momentan ist noch alles unklar, doch ich hoffe mit der Hilfe von euren Beschreibungen krieg ich das hin...!

        Gruss JLearner