JTextArea wird nicht aktualisiert (ActionListener-Problem)

matze999

Mitglied
Hallo,
ich hätte in meiner GUI gerne eine Art "Logger". Ich stelle mir das so vor, dass der Benutzer in der GUI über eine JTextArea darüber informiert wird, was die Anwendung gerade im Hintergrund macht.
Das Problem ist allerdings, dass bei folgendem Code die Zahlen 1-10 aus der zaehle()-Methode leider nicht nach und nach in der Textarea angezeigt werden, sondern erst nach kompletten Durchlauf der Methode.

Java:
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextArea;

public class FrameStarter extends JFrame {

	private JTextArea textArea = new JTextArea();
	private JLabel lbl = new JLabel("Hallo Welt");
	private JButton btn = new JButton("Button");

	public FrameStarter() {
		this.setLayout(new GridLayout(2, 1));
		textArea.setPreferredSize(new Dimension(300, 200));
		btn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				if (e.getSource() == btn) {
					System.out.println("Test");
					machEtwas();
				}
			}
		});
		this.add(lbl);
		this.add(textArea);
		this.add(btn);
		this.pack();
		this.setVisible(true);
	}

	public void machEtwas() {
		AktionNeu aktion = new AktionNeu(textArea);
		aktion.zaehle();
	}

	public static void main(String[] args) {
		FrameStarter frameStarter = new FrameStarter();
		// frameStarter.machEtwas();
	}
}

 class AktionNeu {
	
	JTextArea textArea;
	
	public AktionNeu(JTextArea textarea) {
		this.textArea = textarea;
	}
	
	public void zaehle(){
		for (int i = 0; i < 10; i++) {
			try {
				Thread.sleep(1000);
				textArea.setText(textArea.getText() + "\r\n" + "Zeile: " + i);
//				repaint();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

}

Das Problem scheint hierbei beim ActionListener zu liegen, da bei folgendem Code, wo es keinen ActionListener gibt, die Zahlen 1-10 nacheinander in der Textarea erscheinen

Java:
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextArea;

public class FrameStarter extends JFrame {

	private JTextArea textArea = new JTextArea();
	private JLabel lbl = new JLabel("Hallo Welt");
	private JButton btn = new JButton("Button");

	public FrameStarter() {
		this.setLayout(new GridLayout(2, 1));
		textArea.setPreferredSize(new Dimension(300, 200));
//		btn.addActionListener(new ActionListener() {
//
//			@Override
//			public void actionPerformed(ActionEvent e) {
//				if (e.getSource() == btn) {
//					System.out.println("Test");
//					machEtwas();
//				}
//			}
//		});
		this.add(lbl);
		this.add(textArea);
		this.add(btn);
		this.pack();
		this.setVisible(true);
	}

	public void machEtwas() {
		AktionNeu aktion = new AktionNeu(textArea);
		aktion.zaehle();
	}

	public static void main(String[] args) {
		FrameStarter frameStarter = new FrameStarter();
		frameStarter.machEtwas();
	}
}

 class AktionNeu {
	
	JTextArea textArea;
	
	public AktionNeu(JTextArea textarea) {
		this.textArea = textarea;
	}
	
	public void zaehle(){
		for (int i = 0; i < 10; i++) {
			try {
				Thread.sleep(1000);
				textArea.setText(textArea.getText() + "\r\n" + "Zeile: " + i);
//				repaint();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

}

Meine Frage ist nun, wie kann ich es hinbekommen, dass mit dem ActionListener in der Textarea nach jedem Durchlauf der zaehle()-Methode meine Textarea aktualisiert wird? Also so wie es in dem zweiten Beispiel funktioniert, nur das hier eben kein ActionListener zum Einsatz kommt.

Ich hoffe ihr versteht was ich meine.

Vielen Dank schonmal
 
Zuletzt bearbeitet von einem Moderator:
Das Problem ist allerdings, dass bei folgendem Code die Zahlen 1-10 aus der zaehle()-Methode leider nicht nach und nach in der Textarea angezeigt werden, sondern erst nach kompletten Durchlauf der Methode.

Der Grund dafür ist das deine Schleife bzw. das "sleep(1000)" darin den UI Thread (EDT) blockieren und dieser die Komponenten nicht neuzeichnen kann. (Alles was von einem ActionListener ausgelöst wird läuft im EDT ab)
Sprich du setzt einen neuen Content, willst die Komponente zeichnen lassen und bevor da passiert legst du den Thread schlafen. Sobald die Schleife beendet ist und kein sleep mehr kommt kann der EDT endlich neu zeichnen und du siehst leider alles auf 1x.

Die Lösung hierfür ist das Auslagern von der Schleife in einen neuen Thread.
Im Internet findet man zu diesem Problem genügend Beispiele und Lösungen, einfach mal nach "java UI blocks", "java ui edt blocked" und ähnlichen suchen.

Das Problem scheint hierbei beim ActionListener zu liegen, da bei folgendem Code, wo es keinen ActionListener gibt, die Zahlen 1-10 nacheinander in der Textarea erscheinen

Ohne ActionListener hast du genau das Konstrukt was die Lösung für das Problem mit ActionListener ist 😉
Sobald dein Programm startet gibt es einen Thread der die "main"-Methode abarbeitet. In dieser erstellst du ein neue Objekt von FrameStarter (das Zeichnen dieses Objekte wird vom EDT übernommen).
Die Methode zum Zählen und setzen des neuen Textes wird aber in der "main"-Methode aufgerufen und läuft daher in einem anderen Thread als dem EDT 🙂
 

Zurück
Oben