JTextPane Text Coloring

I'm attempting to make a text editor - a programmer's tool - that colors certain keywords as they are typed in. I'm using a JTextPane and a DocumentListener to wait for keypresses that modify the document text. When each letter is typed, the listener expands the offset and the length to include the entire word. This works, I've checked. If I typehello the program recognizes it as a word. If I press the spacebar and then typetest the program recognizestest as a separate word, the current one.

However, when I try to removeString from the document, or try to insertString with a MutableAttributeSet that is not the LogicalStyle of the document, it gives me this error:

Exception occurred during event dispatching:

java.lang.IllegalStateException: Attempt to mutate in notification

at javax.swing.text.AbstractDocument.writeLock(AbstractDocument.java:1090)

at javax.swing.text.AbstractDocument.insertString(AbstractDocument.java:511)

at Language.Editor.ColorCommand.insertUpdate(ColorCommand.java:63)

at javax.swing.text.AbstractDocument.fireInsertUpdate(AbstractDocument.java:180)

at javax.swing.text.AbstractDocument.insertString(AbstractDocument.java:542)

at javax.swing.JTextPane.replaceSelection(JTextPane.java:159)

at javax.swing.text.DefaultEditorKit$DefaultKeyTypedAction.actionPerformed(DefaultEditorKit.java:801)

at javax.swing.SwingUtilities.notifyAction(SwingUtilities.java:1384)

at javax.swing.JComponent.processKeyBinding(JComponent.java:2078)

at javax.swing.JComponent.processKeyBindings(JComponent.java:2104)

at javax.swing.JComponent.processKeyEvent(JComponent.java:2050)

at javax.swing.JEditorPane.processKeyEvent(JEditorPane.java:1159)

at javax.swing.text.JTextComponent.replaceInputMethodText(JTextComponent.java:2793)

at javax.swing.text.JTextComponent.processInputMethodEvent(JTextComponent.java:2654)

at java.awt.Component.processEvent(Component.java:3558)

at java.awt.Container.processEvent(Container.java:1164)

at java.awt.Component.dispatchEventImpl(Component.java:2593)

at java.awt.Container.dispatchEventImpl(Container.java:1213)

at java.awt.Component.dispatchEvent(Component.java:2497)

at java.awt.EventQueue.dispatchEvent(EventQueue.java:339)

at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:131)

at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:98)

at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)

at java.awt.EventDispatchThread.run(EventDispatchThread.java:85)

Anyone have any idea how I can fix this?

[2741 byte] By [Spaceman40] at [2007-9-26 2:50:26]
# 1

its because ur trying to change the text, which fires a new event, eg. a neverending circle of events. Someone mentioned this method could be used, by placing it inside ur eventhandler:

SwingUtilities.invokeLater(

new Runnable() {

public void run() {

//setCharacterAttributes ...

}});

I havent tried it yet. But it seems easier than any of the solutions I have used for my self.

Stig

slackman at 2007-6-29 10:36:59 > top of Java-index,Archived Forums,Swing...
# 2
HiI am having the same problem .can u please suggest with some solution for this.I have tried SwingUtilities but istill get the exception.
camel10 at 2007-6-29 10:36:59 > top of Java-index,Archived Forums,Swing...
# 3
HiI am having the same problem .can u please suggest with some solution for this.I have tried SwingUtilities but istill get the exception.
camel10 at 2007-6-29 10:36:59 > top of Java-index,Archived Forums,Swing...
# 4

I solved this at the character level rather than the word level but the principle will still apply. It looks like you went down the same road I did originally.

What you really need to do is extend DefaultStyledDocument and override the insertString() method. I used something like:

import java.awt.Color;

import javax.swing.text.*;

public class MyDoc extends DefaultStyledDocument {

static MutableAttributeSet charA, charB, defaultAttr;

public MyDoc() {

charA = new SimpleAttributeSet();

StyleConstants.setForeground(charA, Color.red);

charB = new SimpleAttributeSet();

StyleConstants.setForeground(charG, Color.blue);

defaultAttr = new SimpleAttributeSet();

StyleConstants.setForeground(charN, Color.black);

}

public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {

if (str == null) return;

char[] c = str.toCharArray();

for(int i = 0; i < c.length; i++) {

try {

if (c == 'A' || c == 'a') {

super.insertString(offs+i, String.valueOf(c[i]), charA);

} else if (c == 'B' || c == 'b') {

super.insertString(offs+i, String.valueOf(c[i]), charB);

} else {

super.insertString(offs+i, String.valueOf(c[i]), defaultAttr);

}

} catch (BadLocationException ble) {

throw ble;

}

}

}

}

Then used the following to attach MyDoc to a text pane:

DefaultStyledDocument doc = new MyDoc();

JTextPane jtp = new JTextPane(doc);

Now when I use jtp all a and b characters are coloured, and all other characters are a black.

So for your problem I would suspect you need to create a MutableAttributeSet for each word you wish to highlight. Overide insertString() split/tokenize the str argument. Finally send the tokens with the correct MutableAttributeSet to the insertString() method of the super class.

If you want the text to auto highlight as people are typing then it should simply be a case of identifying the next word boundry, remove the text between the previous and this word boundry, test the word and insert it back using the correct MutableAttributeSet.

Hope this helps

origin236 at 2007-6-29 10:37:00 > top of Java-index,Archived Forums,Swing...