Swing IllegalStateException - Wer kann was damit anfangen?

Goldi

Aktives Mitglied
Hi Leute!

Ich hab da eine Fehlermeldung, mit der ich nix anfangen kann. Ich hab schon alles mögliche versucht. Aber von vorn: Um mein Problem zu schildern, habe ich eine einfache Klasse geschrieben. Sie malt in ein JFrame ein JTextField, das kein "A" als Zeichen zulassen soll. D. h.: Sobald der Anwender ein "A" tippt, wird es sofort wieder gelöscht - so der Plan. Ich bediene mich dazu dem DocumentListener, weil ich hier das Event des "Eintippens" behandeln kann. Hier also der Code und dann die Fehlermeldung:

Code:
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.BadLocationException;

public class TestDocument
extends JTextField
implements DocumentListener {
	
	public TestDocument() {
		super(30);
		getDocument().addDocumentListener(this);
	}
	
	/* Unzulässiges Zeichen: 'A'. Wenn der Text ein 'A' enthält, muss es gerade eingetippt worden
	 * sein, denn die nachfolgende Methode reagiert ja bei jedem 'A' und löscht es wieder raus: */
	public void insertUpdate(DocumentEvent e) {
		if (getText().contains("A")) {
			int pos = getCaretPosition();
			try {
				getDocument().remove(pos - 1, 1);
			} catch (BadLocationException e1) {
				e1.printStackTrace();
			}
		}
	}
	
	// Pflicht-Methoden für den DocumentListener, hier aber unerheblich:
	public void removeUpdate(DocumentEvent e) {}
	public void changedUpdate(DocumentEvent e) {}
	// ------------------------------------------------
	
	public static void main(String args[]) {
		// TestFenster = eine JFrame-Ableitung mit einem Windows-Listener zum Fenster schließen:
		TestFenster wnd = new TestFenster("Test-Fenster");
		wnd.setBounds(10, 10, 500, 50);
		
		// Jetzt das Textfeld mit "A" als unzulässiges Zeichen:
		TestDocument td = new TestDocument();
		wnd.getContentPane().add(td);
		wnd.setVisible(true);
	}
}

Wenn das Programm auf die Zeile
Code:
getDocument().remove(pos - 1, 1);
stößt, wirft das folgende Fehlermeldung aus:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Attempt to mutate in notification
at javax.swing.text.AbstractDocument.writeLock(AbstractDocument.java:1338)
at javax.swing.text.AbstractDocument.remove(AbstractDocument.java:585)
at Test.TestDocument.insertUpdate(TestDocument.java:22)
at javax.swing.text.AbstractDocument.fireInsertUpdate(AbstractDocument.java:202)
at javax.swing.text.AbstractDocument.handleInsertString(AbstractDocument.java:749)
at javax.swing.text.AbstractDocument.insertString(AbstractDocument.java:708)
at javax.swing.text.PlainDocument.insertString(PlainDocument.java:130)
at javax.swing.text.AbstractDocument.replace(AbstractDocument.java:670)
at javax.swing.text.JTextComponent.replaceSelection(JTextComponent.java:1379)
at javax.swing.text.DefaultEditorKit$DefaultKeyTypedAction.actionPerformed(DefaultEditorKit.java:884)
at javax.swing.SwingUtilities.notifyAction(SwingUtilities.java:1662)
at javax.swing.JComponent.processKeyBinding(JComponent.java:2870)
at javax.swing.JComponent.processKeyBindings(JComponent.java:2917)
at javax.swing.JComponent.processKeyEvent(JComponent.java:2833)
at java.awt.Component.processEvent(Component.java:6293)
at java.awt.Container.processEvent(Container.java:2229)
at java.awt.Component.dispatchEventImpl(Component.java:4872)
at java.awt.Container.dispatchEventImpl(Container.java:2287)
at java.awt.Component.dispatchEvent(Component.java:4698)
at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1887)
at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:762)
at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:1027)
at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:899)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:727)
at java.awt.Component.dispatchEventImpl(Component.java:4742)
at java.awt.Container.dispatchEventImpl(Container.java:2287)
at java.awt.Window.dispatchEventImpl(Window.java:2719)
at java.awt.Component.dispatchEvent(Component.java:4698)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:740)
at java.awt.EventQueue.access$300(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:699)
at java.awt.EventQueue$3.run(EventQueue.java:697)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.awt.EventQueue$4.run(EventQueue.java:713)
at java.awt.EventQueue$4.run(EventQueue.java:711)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:710)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

Interessanter Weise springt der Cursor schon wieder um eine Stelle zurück. Es bleibt aber ein halbes "A" andeutungsweise im Textfeld stehen und es gibt eben diesen Fehler. So sieht's aus, wenn ich "jfdaA" eintippe. Der Curser blinkt nach dem Fehler wie gesagt unmittelbar hinter dem kleinen "a":

Textfeld.jpg

Ich habe bereits versucht, vor dieser Zeichenlösch-Zeile (remove...) den DocumentListener auszuschalten und hinterher wieder einzuschalten und das Ganze in eine andere Methode auszulagern. Es ist aber immer der gleiche Fehler. Ohne dass der DocumentListener angesprochen wird, funktioniert die remove-Methode allerdings.

Habt Ihr Rat für mich?:(

Gruß
Goldi
 

Harry Kane

Top Contributor
Du kannst ein Document nicht ändern, solange der DocumentListener da noch seine Finger drauf hat bzw. seine xxxUpdate(DocumentEvent) Methoden noch nicht beendet sind. Ansonsten wäre folgendes möglich: du änderst das Document, der Listener wird aufgerufen, dieser ändern das Document, wodurch der Listener aufgerufen wird, usw.
Wenn du es genau wissen möchtest: Zitat aus der API Documentation von AbstractDocument:
"This class implements a locking mechanism for the document. It allows multiple readers or one writer, and writers must wait until all observers of the document have been notified of a previous change before beginning another mutation to the document.[...] The notification is a beans event notification which does not allow any further mutations until all listeners have been notified.
Das Thema wurde hier im Forum schon besprochen: Bemühe bitte die Forumssuche nach "Attempt to mutate in notification". (und das nächste Mal bitte zuerst suchen und dann fragen).
 
Zuletzt bearbeitet:

Harry Kane

Top Contributor
Ev. solltest du was zur Stärkung deines Erinnerungsvermögens tun. Dasselbe Problem hattest du vor ungefähr einem Jahr, und hast es damals sogar lösen können.
 

Goldi

Aktives Mitglied
Danke für den Hinweis. Ich habe aber jetzt in der API-Dokumentation eine recht gute Lösung gefunden, die ich hier im Forum mit dem Suchbegriff "Attempt to mutate in notification" noch nicht gesehen habe. Deshalb vielleicht ein ganz guter Hinweis für alle, die Textfelder programmieren wollen, die unzulässige Zeichen gar nicht erst annehmen und mit dem DocumentListener scheitern:

Statt dem DocumentListener nehme man einen UndoableEditListener. Der ist viel einfacher und funktioniert einwandfrei. Um zu zeigen, wie's funzt, habe ich mein Eingangsbeispiel einfach umgeschrieben:

Code:
import javax.swing.*;
import javax.swing.event.*;

public class TestDocument
extends JTextField
implements UndoableEditListener {
	
	public TestDocument() {
		super(30);
		getDocument().addUndoableEditListener(this);
	}
	
	/* Unzulässiges Zeichen: 'A'. Wenn der Text ein 'A' enthält, muss es gerade eingetippt worden
	 * sein, denn die nachfolgende Methode reagiert ja bei jedem 'A' und macht es mit undo rückgängig: */
	public void undoableEditHappened(UndoableEditEvent e) {
		if (getText().contains("A"))
			e.getEdit().undo();
	}
	
	public static void main(String args[]) {
		// TestFenster = eine JFrame-Ableitung mit einem Windows-Listener zum Fenster schließen:
		TestFenster wnd = new TestFenster("Test-Fenster");
		wnd.setBounds(10, 10, 500, 50);
		
		// Jetzt das Textfeld mit "A" als unzulässiges Zeichen:
		TestDocument td = new TestDocument();
		wnd.getContentPane().add(td);
		wnd.setVisible(true);
	}
}

Gruß
Goldi
 

Ähnliche Java Themen

Neue Themen


Oben