Swing GUI wird nach invokeLater() langsam

MorrisF

Mitglied
Hallo liebes Java-Forum,
ich habe mit dem WindowBuilder von Eclipse einen JFrame gebastelt. Nun habe ich ein Label, dass in einer Methode mit Text gefüllt wird, dann wird 4 Sekunden gewartet und es kommt zu dem alten Text noch ein neuer.
Hier der Code der Methode:
Java:
private void Warten() throws Exception {
    try {
        LabelText.setText("ich warte gleich . . .");
        new Thread(new Runnable() {
            public void run() {
                try {
                    SwingUtilities.invokeLater(this);
                    Thread.sleep(4000);
                    LabelText.setText(Labeltext.getText() + " ich habe gewartet");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    } catch (Exception e) {
        e.getCause().printStackTrace();
    }
}
Da ich
Java:
SwingUtilities.invokeLater(this);
verwende, habe ich den kleinen Thread erstellt, weil wenn ich nur
Java:
Thread.sleep(4000);
gemacht habe, hat mir nicht "ich warte gleich . . ." ins Label geschrieben (why ever...?).
Auf jeden Fall sehe ich jetzt das "ich warte gleich . . ." und dann nach 4 Sekunden "ich warte gleich . . . ich habe gewartet".
Mein Problem ist jetzt aber, dass nach dieser Methode meine ganze GUI hängt. Wenn man zb einen Button anklickt, dann wird der klick erst nach ca 10 Sekunden ausgeführt.
Woran könnte das liegen?
Und kennt jemand vielleicht einen schöneren Weg, um an mein Ziel zu kommen?

Besten Dank im Voraus, für eure Hilfe!
MFG
Morris
 
Weil du dadurch den Thread der GUI (EDT) pausiert hast und damit deine GUI einfriert.
Und kennt jemand einen schöneren Weg, um an mein Ziel zu kommen?
Über die javax.swing.Timer Klasse
Java:
public class Test {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setSize(500,500);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final JLabel labelText = new JLabel("");

        JButton button = new JButton("Press me");
        button.addActionListener(event -> {
            labelText.setText("ich warte gleich . . .");
            Timer timer = new Timer(4000, e -> labelText.setText(labelText.getText() + " ich habe gewartet"));
            timer.start();
        });

        frame.add(labelText);
        frame.add(button, BorderLayout.SOUTH);
        frame.setVisible(true);
    }
}
 
Danke erstmal, für die schnelle Antwort!
leider bin ich etwas überfragt, was du im Code mit den Pfeilen
Java:
button.addActionListener(event -> {
            labelText.setText("ich warte gleich . . .");
            Timer timer = new Timer(4000, e -> labelText.setText(labelText.getText() + " ich habe gewartet")
in diesem abschnitt machst...
Habe sowas noch nie gesehen (Sorry, mache noch nicht soo lange Java)
 
Das ganze nennt sich Lambda-Ausdruck.
Du musst es aber auch nicht "mit den Pfeilen" machen, sondern kannst ganz normal eine anonyme innere Klasse erstellen:
Java:
button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent event) {
        labelText.setText(...);
        Timer timer = ....
        timer.start();
    }
});
 
Ahh, das sieht schon verständlicher aus! xD
Danke!
Hätte da noch ein paar Fragen:
Warum braucht der Timer das ActionEvent? Gibt es auch Timer, die das nicht brauchen?
Weil ich rufe meine Warten() Methode nicht nur von einem Button aus auf und außerhalb vom Button hab ich ja dann kein ActionEvent.
 
Der Konstruktor von javax.swing.Timer erwartet 2 Parameter. Der erste delay ist die Zeit vor dem Ausführen der Aktion. Über den zweiten Parameter, welcher vom Typ ActionListener ist, wird definiert, was ausgeführt werden soll. Du brauchst hier also kein ActionEvent des Buttons. Du gibst über den ActionListener nur an, "was der Timer ausführen soll".
Java:
public static void main(String[] args) {
    Timer timer = new Timer(1000, new ActionListener() {
         @Override
         public void actionPerformed(ActionEvent event) {
              System.out.println("Hallo Welt");
         }
    });
    timer.start(); 
}
 
Verstehe! Vielen Dank!
in meinem Fall soll er ja 4 Sekunden warten... muss ich dann wieder ein
Code:
Thread.sleep(4000);
machen? aber dann hab ich ja wieder das Problem, dass die GUI hängt... oder?
 
sondern will nur einmal 4 Sekunden warten
Das ist einfach und Du hattest das Problem schon fast gelöst:
Java:
        new Thread(new Runnable() {
            public void run() {
                try {
                    Thread.sleep(4000);
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            LabelText.setText(Labeltext.getText() + " ich habe gewartet");
                        }
                    });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
 
Alternativ funktioniert das natürlich auch mit Timer:
Java:
    Timer timer = new Timer(4000, new ActionListener() {
         @Override
         public void actionPerformed(ActionEvent event) {
             LabelText.setText(Labeltext.getText() + " ich habe gewartet");
         }
    });
    timer.setRepeats(false); // nur einmal
    timer.start();
 
ja, ich denke schon.
Timer macht alles zyklisch,(außer man macht
Code:
setRepeats(false):
)
und
Code:
Thread.sleep();
wartet nur einmal.

Mein Problem war ja, dass meine GUI wegen dem
Code:
Thread.sleep();
eingefroren is, was ja jetzt mit der richtigen Verwendung von
Code:
invokeLater
behoben wurde.
...oder?
 
Das ist ein Teil davon. Speziell geht es mir darum:
Java:
        new Thread(new Runnable() {
            public void run() {
                try {
                    SwingUtilities.invokeLater(this);
                    Thread.sleep(4000);
                    LabelText.setText(Labeltext.getText() + " ich habe gewartet");

Du erstellst ja einen neuen Thread und in dem Runnable rufst Du Thread.sleep() auf. Warum aber friert dann die GUI ein?
 
Zuerst habe ich mich gewundert, dass keine Queue überläuft....

Es ginge natürlich auch um in seinem Schema zu bleiben wobei nüschts einfriert und was schon sehr sehr genau ist:
Java:
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
/**
 */
public class Test {
    public static void main(String[] args) {
        JFrame f = new JFrame();
        JLabel l = new JLabel();

        f.add(l);
        f.setSize(300, 100);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(4000);
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            l.setText("4 Sek. gewartet: " + (System.currentTimeMillis() / 1000) % 1000);
                        }
                    });
                    new Thread(this).start();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}


@mihe7 akzeptabel?
 

Zurück
Oben