Swing Swing und Thread.sleep()

babuschka

Top Contributor
Hallo!

Ich möchte mein Problem anhand eines sehr einfachen Beispiels erklären.

Ich habe einen JDialog mit einem Button und einem Label erstellt. Beim Klick auf einen Start Button möchte ich im Label counterLabel mit einem bestimmten zeitlichen Abstand hochzählen. Ich hab das mit Thread.sleep(100) versucht:

Java:
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JComponent;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;


public class NewJDialog extends javax.swing.JDialog {

	{
		try {
			javax.swing.UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
		} catch(Exception e) {
			e.printStackTrace();
		}
	}

	private JButton Start;
	private JLabel counterLabel;

	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				JFrame frame = new JFrame();
				NewJDialog inst = new NewJDialog(frame);
				inst.setVisible(true);
			}
		});
	}
	
	public NewJDialog(JFrame frame) {
		super(frame);
		initGUI();
	}
	
	private void initGUI() {
		try {
			GridLayout thisLayout = new GridLayout(1, 1);
			thisLayout.setHgap(5);
			thisLayout.setVgap(5);
			thisLayout.setColumns(1);
			getContentPane().setLayout(thisLayout);
			{
				Start = new JButton();
				GroupLayout StartLayout = new GroupLayout((JComponent)Start);
				Start.setLayout(null);
				getContentPane().add(Start);
				Start.setText("start");
				Start.setPreferredSize(new java.awt.Dimension(150, 100));
				Start.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent evt) {
						StartActionPerformed(evt);
					}
				});
				StartLayout.setHorizontalGroup(StartLayout.createParallelGroup());
				StartLayout.setVerticalGroup(StartLayout.createParallelGroup());
			}
			{
				counterLabel = new JLabel();
				getContentPane().add(counterLabel);
				counterLabel.setText("");
			}
			pack();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private void StartActionPerformed(ActionEvent evt) {
		counterLabel.setText("");
		
		for(int counter = 0; counter < 10; counter++)
		{
			System.out.println(counter);
			counterLabel.setText(String.valueOf(counter));
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

}


Mein Problem:
Die println() Anweisung wird in jedem Schleifendurchlauf auf der Console angezeigt.
Der Text des counterLabels wird nur einmal ganz am Ende (auf 9) aktualisiert.

Warum wird der Text im counterLabel nicht alle 100 Millisekunden aktualisiert? 🙁
Habe ich einen komplett falschen Ansatz?
 
actionPerformed wird auf dem GUI-Thread(EDT) ausgeführt, d.h. du legst auch diesen schlafen mit Thread.sleep...das sollte man a) eh vermeiden da Aktionen auf dem EDT schnell ausgeführt werdne sollten und b) kommt es dann zu solchen Problemen. Starte einen neuen Thread und führe dort deinen Code aus(das setText dann wieder auf dem EDT ausführen, also mit invokeLater wie auch schon in der main..) oder evtl. direkt mit Timer ?!
 
Danke für deine Antwort.

Gibt es in Java eine andere einfache Möglichkeit um "zu warten" ohne dass ich den Thread schlafenlege und mir somit das Neuzeichnen der GUI blockiere?
 
Zuletzt bearbeitet von einem Moderator:
???:L Das verstehe ich nicht, kannst du dazu vllt auch mal ein Beispiel geben?

Also dein o.g. Beispiel könntest du z.B. wie folgt abändern (vllt beantwortet das schon deine Frage? ):
Java:
private Timer timer; 
//.......
	private void StartActionPerformed(ActionEvent evt) {
		final int counter = 0;
		Start.setEnabled(false); //Variablen(start) besser klein schreiben !!!
		timer = new Timer(1000, new ActionListener() {
			int cnt = counter;
			@Override
			public void actionPerformed(ActionEvent e) {
				counterLabel.setText(String.valueOf(cnt++));
				if (cnt == 10) {
					timer.stop();
					Start.setEnabled(true);
				}
			}
		});
		timer.setInitialDelay(0);
		timer.start();
	}

Ansonsten wie schon gesagt, einen neuen Thread starten..da kannst du dann auch Thread.sleep aufrufen oder sonst was tun...
 
Danke du hast mir sehr geholfen.

Eine Frage habe ich noch zu deinem Code:
Wozu hast du die Variable counter bzw. kann ich diese Variable nicht einfach weglassen? :noe:

Java:
	private void StartActionPerformed(ActionEvent evt) {
        Start.setEnabled(false);
        timer = new Timer(200, new ActionListener() {
            int cnt = 0;
            public void actionPerformed(ActionEvent e) {
                counterLabel.setText(String.valueOf(cnt++));
                if (cnt == 10) {
                    timer.stop();
                    Start.setEnabled(true);
                }
            }
        });
        timer.setInitialDelay(0);
        timer.start();
    }
 

Neue Themen


Zurück
Oben