Swing GUI-Änderungen mit invokeLater

X

Xenya

Gast
Hallo,
ich habe eine Verständnisfrage zum Thema GUI-Änderungen via invokeLater anstoßen.

Alle Änderungen die die GUI betrifft sollte man ja Mittels invokeLater ausführen.
Soweit ich weiß, werden alle Aktivitäten von der GUI ebenfalls damit umgesetzt. Das heißt, die Methode die von einem Button-Klick oder von der Veränderung in einem Text-Field aufgerufen wird, laufen bereits als "invokeLater Thread". Ist dies richtig?

Muss ich in einem "invokeLater Thread" die GUI-Änderungen wieder per invokeLater aufrufen? Ich habe dies bis jetzt nicht gemacht, da ich dachte der "invokeLater Thread" von einem Button klick reicht.

Wenn dies doch nicht reicht, bedeutet es wenn ich 3 verschiedene Textfelder verändern will muss ich 3 invokeLater-Threads aufmachen?


Wie ich da im Moment darauf komme:
Meine GUI lief bis jetzt einwandfrei aber nun habe ich einen Funktion hinter der Änderung einer JList eingebaut, die mir Probleme macht. Hier erst mal die wichtigsten Codeschnipssel (falls ich was wichtiges weggelassen habe, sagt es):
Java:
JTextField textField = new JTextField();
textField.getDocument().addDocumentListener(new DocumentListener()
{
	  public void changedUpdate(DocumentEvent e)
	  {
		  //do something
	  }
	  public void removeUpdate(DocumentEvent e)
	  {
		  //do something
	  }
	  public void insertUpdate(DocumentEvent e)
	  {
		  //do something
	  }
});

JList list = new JList();
list.addListSelectionListener(new ListSelectionListener()
{
	public void valueChanged(ListSelectionEvent arg0)
	{
		 textField.setText("");
	}
});

Wenn ich nun was in der Liste anwähle und relativ zügig danach etwas in "textField" schreibe wird die folgende Fehlermeldung geworfen:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Attempt to mutate in notification
(Exception wird ausgehend von der Zeile textField.setText(""); geworfen).

Habe mal gegoogelt und habe gelesen, dass man dies umgehen kann, wenn man die GUI-Änderungen in invokeLater aufruft. Da ich aber dachte, dass durch die beiden Listener es eh schon in einem "invokeLater Thread" läuft kann ich mir ein neues invokeLater sparen.
Bevor ich es nun abändere (weil ich dann viel nachziehen muss) wollte ich mir mit eurer Hilfe erstmal Klarheit verschaffen, was ich genau machen muss.

Danke für eure Tipps
 

xehpuk

Top Contributor
Hey,

der Thread nennt sich "Event Dispatching Thread" (meist zu EDT abgekürzt) und wird afaik bei Events nativ vom Betriebssystem angestoßen. Es wird da also nicht
Code:
invokeLater()
aufgerufen.

Das heißt, die Methode die von einem Button-Klick oder von der Veränderung in einem Text-Field aufgerufen wird, laufen bereits als "invokeLater Thread". Ist dies richtig?
Ja.

Muss ich in einem "invokeLater Thread" die GUI-Änderungen wieder per invokeLater aufrufen?
Nein.

Wenn dies doch nicht reicht, bedeutet es wenn ich 3 verschiedene Textfelder verändern will muss ich 3 invokeLater-Threads aufmachen?
Nein, du kannst beliebig viele Komponenten verändern. Es kommt nur darauf an, dass dies im EDT geschieht.

Hier erst mal die wichtigsten Codeschnipssel (falls ich was wichtiges weggelassen habe, sagt es):
Du hast in der Tat das Wichtigste weggelassen. Dein Fehler hat gar nichts mit dem EDT zu tun. Das Problem liegt in mindestens einer deiner
Code:
*Update()
-Methoden des
Code:
DocumentListener
. Die betroffene Methode dürfte auch im Stacktrace erscheinen. Und das Problem ist, dass du innerhalb einer der Methoden den Inhalt des Dokuments änderst. Das ist dann auch mit der Meldung "Attempt to mutate in notification" gemeint.
Du könntest es wirklich so umgehen, dass du den Code, der den Inhalt des Dokuments verändert, über
Code:
invokeLater()
laufen lässt, aber das scheint mir keine gute Lösung zu sein.
 
V

vanny

Gast
Ich handhabe es iin der Regel so, dass alle Methoden, die keine erwähnenswerte Rechnezeit benötigen ohne seperaten Thread und somit auch ohne invokeLater() auskommen.
Erst wenn rechenintensive Prozesse ins Spiel kommen wird ein seperater Thread bemüht und teilt dann nur die GUI-relevanten Ergebnisse per invokeLater() mit oder ändert schlichtweg das Model falls vorhanden und die GUI aktualisiert sich gefälligst von selbst:bae:

Gruß Vanny
 

Marco13

Top Contributor
oder ändert schlichtweg das Model falls vorhanden und die GUI aktualisiert sich gefälligst von selbst:bae:

Auf welchem Thread, das ist die Frage:
Java:
TreeModel m = ...
JTree t = new JTree(m);

Thread t = new Thread(new Runnable()
{
    @Override
    public void run()
    {
        m.changeSomething();
    }
});
t.start();
Das changeSomething benachrichtigt alle Listener, unter anderem auch den JTree - aber das passiert NICTH auf dem EDT. (Oder anders, ganz konkret: Die Modell-Klassen und die Swing-Klassen kümmern sich NICHT darum, dass Änderungen nur auf dem EDT stattfinden - darum muss sich allein der Programmierer kümmern)
 
X

Xenya

Gast
Hallo,
danke für eure Antworten.

Habe gerade schon einen sehr großen Text geschrieben, in dem ich versucht habe das Programm genauer zu erklären damit ihr mir bei der Problemsuche helfen könnt.

Mir ist am Ende ein Licht aufgegangen, weshalb ich grad das Problem gefunden habe.


Also das Textfeld legt sobald ein Text eingegeben wird einen neuen Eintrag an, der anschließend in der JList angezeigt wird.

Hinter dem JList Model steht eine eigens geschriebene Klasse, die beim Aufruf von addNewObject alle ListDataListener mit der Methode listener.intervalAdded aufruft und ihnen den Index übergeben, wo etwas geändert wurde.
Jetzt kommt das Problem, dass ich irgend wie nicht ganz nachvollziehen kann und ich bis grad nicht beachtet habe:
Bei Aufruf von intervalAdded wird (immer? unter bestimmten Umständen?) die valueChanged Methode der Liste aufgerufen.
Das heißt:
"Textfeldeingabe" -> "addInModel" -> "valueChangeInList" -> "setTextOnTextfeld"
Dem zu folge wird eine Textfeldeingabe gemacht die durch eine Eingabe in das Textfeld ausgelöst wurde.

Um dieses Problem zu umgehen habe ich nun die valueChanged Methode so erweitert:
Java:
JList list = new JList();
list.addListSelectionListener(new ListSelectionListener()
{
    public void valueChanged(ListSelectionEvent arg0)
    {
        if(!internalChange)
             textField.setText("");
    }
});

Bevor intervalAdded aufgerufen wird wird es auf true gesetzt, danach auf false. Jetzt geht es.

Wirklich schön finde ich es nicht. Vor allem, da ich es wie oben angemerkt nicht kapiere (vor der Änderung war nichts ausgewählt und sollte eigentlich durch die Eingabe auch nicht).

Danke für eure Hilfe
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
P JavaFX Änderungen am Datenmodell visuell nicht sichtbar AWT, Swing, JavaFX & SWT 3
G JTextField Änderungen überprüfen AWT, Swing, JavaFX & SWT 4
W Swing JPanel nur einmal nach mehreren Änderungen neu zeichnen AWT, Swing, JavaFX & SWT 1
D Swing JTextComponent markieren bei Änderungen AWT, Swing, JavaFX & SWT 5
S JTable übernimmt Änderungen nicht AWT, Swing, JavaFX & SWT 2
G JavaFX TableView - Änderungen werden nicht übernommen. AWT, Swing, JavaFX & SWT 3
S Swing Auf Änderungen eines Models in der View einer JTable reagieren AWT, Swing, JavaFX & SWT 1
B Row und Cell Änderungen feststellen AWT, Swing, JavaFX & SWT 3
D Änderungen einer Card des CardLayouts zur Laufzeit AWT, Swing, JavaFX & SWT 6
M Swing Änderungen eines TextFelds und JOptionPane AWT, Swing, JavaFX & SWT 5
J JTable DefaultTableModel - Änderungen feststellen AWT, Swing, JavaFX & SWT 8
C Übernahme von Änderungen in einer JTable AWT, Swing, JavaFX & SWT 7
J Verzögerung bei Änderungen der Anzeige abwarten AWT, Swing, JavaFX & SWT 5
R Swing 2 jTables -2 Models - 1 Datenklasse: Änderungen AWT, Swing, JavaFX & SWT 11
M In Jlist auf Änderungen von mehreren JLabels reagieren AWT, Swing, JavaFX & SWT 3
Pithecanthropus [gelöst ]ActionListener soll nur Änderungen "bemerken" AWT, Swing, JavaFX & SWT 2
B Keine Änderungen an JLabel durch Array möglich AWT, Swing, JavaFX & SWT 12
U Beste Möglichkeit JTable-Änderungen in DB zu schreiben? AWT, Swing, JavaFX & SWT 14
S Textfeld soll auf Änderungen von nutzer und program reagiern AWT, Swing, JavaFX & SWT 3
P Änderungen in xml datei speichern AWT, Swing, JavaFX & SWT 7
A JTable Änderungen anzeigen (DefaultTableModel) AWT, Swing, JavaFX & SWT 5
T JTable Änderungen AWT, Swing, JavaFX & SWT 2
M Änderungen an JPanel nicht sichtbar AWT, Swing, JavaFX & SWT 8
S Swing: Änderungen in JLabel oder JTextField sofort anzeigen AWT, Swing, JavaFX & SWT 3
M Swing GUI wird nach invokeLater() langsam AWT, Swing, JavaFX & SWT 19
B Frame hängt sich auf trotz invokeLater AWT, Swing, JavaFX & SWT 1
Ollek Swing SwingUtilities invokeLater und invokeAndWait AWT, Swing, JavaFX & SWT 4
B Swing invokeLater nötig beim GUI erstellen? AWT, Swing, JavaFX & SWT 10
W Swing SwingUtilities.invokeLater wie konsequent anwenden? AWT, Swing, JavaFX & SWT 3
Dit_ SwingUtilities.invokeLater und Modaler JDialog AWT, Swing, JavaFX & SWT 11
Dit_ Frage zum Thema SwingUtilities.invokeLater AWT, Swing, JavaFX & SWT 5
H invokeLater Problem AWT, Swing, JavaFX & SWT 8
I Swing Wann invokeLater() verwenden? AWT, Swing, JavaFX & SWT 7
G Frage zu SwingUtilities.invokeLater AWT, Swing, JavaFX & SWT 16
E einfache Frage zu invokeLater() AWT, Swing, JavaFX & SWT 4
G Frage zu SwingUtilities.invokeLater AWT, Swing, JavaFX & SWT 9
G Schachtelung bei invokeLater AWT, Swing, JavaFX & SWT 4
B SwingUtilities.invokeLater() AWT, Swing, JavaFX & SWT 12
F invokeLater() vs synchronized(Object) AWT, Swing, JavaFX & SWT 5
T invokeLater - Wann? AWT, Swing, JavaFX & SWT 29
L invokeLater in der main-Methode AWT, Swing, JavaFX & SWT 6
D GUI in JFrame mit invokeLater verändern AWT, Swing, JavaFX & SWT 5
M GUI in Verbindung mit invokeLater() bzw. invokeAndWait() AWT, Swing, JavaFX & SWT 2

Ähnliche Java Themen

Neue Themen


Oben