javaswinguser-interfacejtextfield

How do you forcibly set text in an active JTextField without throwing an exception?


JTextField's SetText method throws an exception whenever I try to set the contents while the field has focus. I need that to change, because I want to input a very precise number of characters, and once that character count is reached the field needs to be cleared while still having focus so the next set of characters can immediately be added without pushing any buttons.

I tried creating a static method that would re-create the text field from scratch every time it filled up, allowing a sort of recursive regeneration of the field each time. The method simply didn't do anything. For reference, basically everything in this program is static because it's a very simple application and I basically just want to access every important variable from "main".

Trying to set the text while the field has focus shows the following:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Attempt to mutate in notification
    at javax.swing.text.AbstractDocument.writeLock(Unknown Source)
    at javax.swing.text.AbstractDocument.replace(Unknown Source)
    at javax.swing.text.JTextComponent.setText(Unknown Source)
    at onlypack.ProgramMain$3.insertUpdate(ProgramMain.java:118)
    at javax.swing.text.AbstractDocument.fireInsertUpdate(Unknown Source)
    at javax.swing.text.AbstractDocument.handleInsertString(Unknown Source)
    at javax.swing.text.AbstractDocument.insertString(Unknown Source)
    at javax.swing.text.PlainDocument.insertString(Unknown Source)
    at javax.swing.text.AbstractDocument.replace(Unknown Source)
    at javax.swing.text.JTextComponent.replaceSelection(Unknown Source)
    at javax.swing.text.DefaultEditorKit$DefaultKeyTypedAction.actionPerformed(Unknown Source)
    at javax.swing.SwingUtilities.notifyAction(Unknown Source)
    at javax.swing.JComponent.processKeyBinding(Unknown Source)
    at javax.swing.JComponent.processKeyBindings(Unknown Source)
    at javax.swing.JComponent.processKeyEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    at java.awt.Container.processEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.KeyboardFocusManager.redispatchEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$500(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

Solution

  • you can't modify the document from inside a Document LIstener

    Correct, you need to wait until the Document is in a state to accept input.

    One way to do this is to wrap your code in the DocumentListener in a SwingUtilties.invokeLater(). This will place the code at the end of the Event Dispatch Thread and it will execute after the Document has finished updating itself.

    Another option, instead of using a DocumentListener, it to use a DocumentFilter. This intercepts the text BEFORE it is added to the Document. So you could just simply clear the Document when the specified number of characters has been input. Read the section from the Swing tutorial on Implement a DocumentFilter for more information.