Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
284 views
in Technique[技术] by (71.8m points)

java - JTextPane highlighting issue

The last days I have been trying to implement a highlighting feature in a small text editor. For some reason I get a strange result:

enter image description here

The given example should highlight each "dolor" - the first occurences are correctly found and highlighted but the next ones aren't.

Here is the code I wrote so far:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.DefaultHighlighter.DefaultHighlightPainter;
import javax.swing.text.DefaultStyledDocument;

/**
 * Highlighting created on 04.11.2013<br>
 * <br>
 * Specification:<br>
 */
public class Highlighting extends JFrame implements MouseListener {

    private JScrollPane scrollPane;
    private JTextPane textPane;

    private DefaultHighlighter highlighter;
    private DefaultHighlightPainter painter;

    public static void main(String[] args) {
        new Highlighting().setVisible(true);
    }

    /**
     * 
     */
    public Highlighting() {
        this.initialize();
        this.build();
        this.configure();
    }

    /**
     *
     */
    public void initialize() {
        this.scrollPane = new JScrollPane();
        this.textPane = new JTextPane();
        this.highlighter = new DefaultHighlighter();
        this.painter = new DefaultHighlightPainter(Color.RED);
    }

    /**
     *
     */
    public void build() {
        this.add(this.scrollPane);
    }

    /**
     *
     */
    public void configure() {
        this.scrollPane.setViewportView(this.textPane);
        this.textPane.setHighlighter(this.highlighter);
        this.textPane.addMouseListener(this);
        this.textPane.setDocument(new DefaultStyledDocument());

        this.setPreferredSize(new Dimension(400, 500));
        this.pack();
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    /**
     * 
     */
    private void highlight() {
        this.highlighter.removeAllHighlights();

        String selectedText = this.textPane.getSelectedText();
        String text = this.textPane.getText();

        int wordlength = selectedText.length();

        int index = 0;
        while ((index = text.indexOf(selectedText, index)) != -1) {

            try {
                this.highlighter.addHighlight(index, index + wordlength, this.painter);
            } catch (BadLocationException e) {
                e.printStackTrace();
            }

            index += wordlength;
        }
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        if (e.getClickCount() == 2) {
            this.highlight();
        }
    }

    @Override
    public void mousePressed(MouseEvent e) {}

    @Override
    public void mouseReleased(MouseEvent e) {}

    @Override
    public void mouseEntered(MouseEvent e) {}

    @Override
    public void mouseExited(MouseEvent e) {}

}

Does this has something to do with the line separators ( ) ?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

A JTextComponent's getText() and A JTextPane/JEditorPane's getText() has different implementation. JTextPane/JEditorPane uses EditorKit to write the document content(text) to a StringWriter and then return the text with formatting and inserting a line/paragraph break into the document. But the JTextCompoent returns document content directly by:

document.getText(0, document.getLength());

You will better understand if you try to compare the length : jTextPane1.getText().length() and jTextPane1().getDocument().getLength().

Reproducing the difference in length by inserting string with:

DefaultStyleDocument.insertString(0, str, primaryStyle)

when str = "I
 not"   ; document length = 6, getText().length = 7
when str = "I
 not" ; document length = 7, getText().length = 8
when str = "I

 not" ; document length = 7, getText().length = 9!

So, in your high-lighting text program try reading the content text using:

DefaultStyledDocument document = (DefaultStyledDocument) jTextPane1.getDocument();
try {
    contText = document.getText(0, document.getLength());
} catch (BadLocationException ex) {
     Logger.getLogger(JTextPaneTest.class.getName()).log(Level.SEVERE, null, ex);
 }

Then search for your selected text position in the contText as you were doing and you should be good to go. Because, highlighter.addHighlight(int p0, int p1, Highlighter.HighlightPainter p) uses the document for position offset.

Use CaretListener:

To Highlight upon text selection, It is better to use CaretListener, no need to add mouse and key board selection handling code at all:

enter image description here

jTextPane1.addCaretListener(new CaretListener() {
        public void caretUpdate(CaretEvent evt) {
            if(evt.getDot() == evt.getMark())return;

    JTextPane txtPane = (JTextPane) evt.getSource();
    DefaultHighlighter highlighter = (DefaultHighlighter) txtPane.getHighlighter();
    highlighter.removeAllHighlights();
    DefaultHighlightPainter hPainter = new DefaultHighlightPainter(new Color(0xFFAA00));
    String selText = txtPane.getSelectedText();
    String contText = "";// = jTextPane1.getText();

    DefaultStyledDocument document = (DefaultStyledDocument) txtPane.getDocument();

    try {
        contText = document.getText(0, document.getLength());
    } catch (BadLocationException ex) {
        Logger.getLogger(JTextPaneTest.class.getName()).log(Level.SEVERE, null, ex);
    }

    int index = 0;

    while((index = contText.indexOf(selText, index)) > -1){

        try {
            highlighter.addHighlight(index, selText.length()+index, hPainter);
            index = index + selText.length();
        } catch (BadLocationException ex) {
            Logger.getLogger(JTextPaneTest.class.getName()).log(Level.SEVERE, null, ex);
           //System.out.println(index);
        }
       }
        }
    });

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...