1

I'm created a jtextpane with two different styles: one for the numbers (pink foreground) and a default style for the rest (black foreground). I have added a keylistener (I use the KeyReleased function) at the jtextpane in order to handle the new pressed character, but I have a problem during writing. The scenario is the following:

  • The text is: hello 123
  • And the 'hello' text is black and the number '123' is pink.
  • Now the caret is between '1' and '2', I press 'a' and occurring something strange.
  • The character 'a' becomes pink and then black.

Why does it become black for a short time?

I handle the KeyReleased in this way:

  1. I set all the text with the default style (the clean phase)
  2. I will change the foreground in pink for only numbers

This is the example:

import java.awt.Color;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.StringTokenizer;

import javax.swing.JFrame;
import javax.swing.JTextPane;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;


public class Example extends JFrame {

JTextPane pn = new JTextPane();
public Example() {

    addDefaultStyle(pn);
    addNumberStyle(pn);

    pn.addKeyListener(new KeyAdapter() {

        @Override
        public void keyReleased(KeyEvent arg0) {
            String text = pn.getText();


            pn.getStyledDocument().setCharacterAttributes(0, text.length(), pn.getStyle("default"), true);

            StringTokenizer ts = new StringTokenizer(text, " ");

            while(ts.hasMoreTokens()){
                String token = ts.nextToken();

                try{
                    Integer.parseInt(token);

                    pn.getStyledDocument().setCharacterAttributes(text.indexOf(token), token.length(), pn.getStyle("numbers"), true);

                }catch(Exception e){

                    pn.getStyledDocument().setCharacterAttributes(text.indexOf(token), token.length(), pn.getStyle("default"), true);
                }
            }

        }
    });

    getContentPane().add(pn);
    setSize(400, 400);
    setLocationRelativeTo(null);
    setVisible(true);
}

private void addDefaultStyle(JTextPane pn){
    Style style = pn.addStyle("default", null);

    pn.setForeground(Color.blue);
    pn.setBackground(Color.WHITE);

    StyleConstants.setForeground(style, pn.getForeground());
    StyleConstants.setBackground(style, pn.getBackground());
    StyleConstants.setBold(style, false);
}

private void addNumberStyle(JTextPane pn){
    Style style = pn.addStyle("numbers", null);

    StyleConstants.setForeground(style, Color.PINK);
    StyleConstants.setBackground(style, Color.WHITE);
    StyleConstants.setBold(style, true);
}

public static void main(String args []){
    new Example();
}
}
kleopatra
  • 51,061
  • 28
  • 99
  • 211
Paul
  • 147
  • 1
  • 2
  • 5

3 Answers3

1
Community
  • 1
  • 1
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • Thank you, I've seen your link, but I still have the same problem. Why if I change the foreground of a text from pink to black, and then I put a new character into the text I' will have a new character pink? – Paul Sep 24 '12 at 10:52
  • @Paul for better help sooner post (very short and runnable) an [SSCCE](http://sscce.org/) demonstrated your issue with Document, Pattern and HightLighter – mKorbel Sep 24 '12 at 11:59
  • use DocumentListener ([override all methods with output to the same a new void](http://stackoverflow.com/a/7284706/714968) ), put there [Pattern](http://stackoverflow.com/a/6421385/714968) – mKorbel Sep 25 '12 at 15:40
  • Ok I going to try with document listener. – Paul Sep 25 '12 at 19:07
0
  1. Why does it become black?
    • It should. 1a2 is not a valid Integer. It changes to pink for a short time bcos your formatting happens only after the event. When you write in between pink characters, your text will be pink (until you change it).

Other points:

  • Since you need to format only numbers, then no need to apply 'default' style to other characters that are already 'default'.
  • In my solution, I went by digits. If you want whole numbers instead (where "1a2" will be false), then go ahead with the StringTokenizer. Just know that if there's a number at the end of the sentence, it will not be matched - I am 12..

Code:

public void keyReleased(KeyEvent arg0) {
    applyStyle();
}

public void applyStyle() {
    String text = pn.getText();
    pn.getStyledDocument().setCharacterAttributes(0, text.length(), pn.getStyle("default"), true);

    char[] textChar = text.toCharArray();
    for(int i=0, len=textChar.length; i<len; i++){
        if(Character.isDigit(textChar[i]))
            pn.getStyledDocument().setCharacterAttributes(i, 1, pn.getStyle("numbers"), true);
    }
}

Alternatively, I would have used a DocumentListener instead of a KeyListener.

public class SmartTextPane extends JTextPane implements DocumentListener{

    public SmartTextPane(){ 
        super();
        this.getDocument().addDocumentListener(this);
    }

    public void changedUpdate(DocumentEvent e){ 
        applyStyle();
    }
    public void insertUpdate(DocumentEvent e){} 
    public void removeUpdate(DocumentEvent e){}

    //define your style functions
}
davidXYZ
  • 719
  • 1
  • 8
  • 16
0

I had almost the same problem, where i do highlighting and did something like inputTextDocModel.setCharacterAttributes(0, inputTextDocModel.getLength() + 1, styleNormal, true); to switch the highlighted characters to normal. But this actually will apply for the existing characters, but does not apply to the caret's attributes. So the new character still appearing 'highlighted' although i already set all to 'normal'.

I did something like follows, which is overiding replace() in DocumentFilter

public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs)
            throws BadLocationException {
 // styleNormal is the 'normal' Style, styleMarked is the 'highlighting' style

     inputTextDocModel.setCharacterAttributes(0, inputTextDocModel.getLength() + 1, styleNormal, true);
     super.replace(fb, offset, length, text, styleNormal.copyAttributes());

  // this is to make sure the caret update its style from 'highlighter' to 'normal' - 
  // assume variable 'editorkit' assigned as StyledEditorKit and has been assigned to the component 
  // by textcomponent.setEditorKit(editorkit)

     editorkit.getInputAttributes().removeAttributes(styleMarked.getAttributeNames());
}

I hope this 'solution' helps


Update: Actually we can simply use the StyledEditorKit to retrieve and modify the caret's attribute and remove the highlighting attribute. So I updated the code above which implement the correct solution.

Mohd Yunus
  • 11
  • 2