如何更改JTextPane中特定单词的颜色?

如何在用户input时更改JTextPane中特定单词的颜色? 我应该重写JTextPane paintComponent方法吗?

覆盖paintComponent不会帮助你。

这不是一个容易的,但也不是不可能的。 像这样的东西将帮助你:

 DefaultStyledDocument document = new DefaultStyledDocument(); JTextPane textpane = new JTextPane(document); StyleContext context = new StyleContext(); // build a style Style style = context.addStyle("test", null); // set some style properties StyleConstants.setForeground(style, Color.BLUE); // add some data to the document document.insertString(0, "", style); 

你可能需要调整这个,但至less它会告诉你从哪里开始。

不,你不应该重写paintComponent()方法。 相反,你应该使用StyledDocument 。 你也应该由你自己来划定这些单词。

这里是演示,在打字时将“public”,“protected”和“private”变为红色,就像简单的代码编辑器一样:

在这里输入图像描述

 import javax.swing.*; import java.awt.*; import javax.swing.text.*; public class Test extends JFrame { private int findLastNonWordChar (String text, int index) { while (--index >= 0) { if (String.valueOf(text.charAt(index)).matches("\\W")) { break; } } return index; } private int findFirstNonWordChar (String text, int index) { while (index < text.length()) { if (String.valueOf(text.charAt(index)).matches("\\W")) { break; } index++; } return index; } public Test () { setDefaultCloseOperation(EXIT_ON_CLOSE); setSize(400, 400); setLocationRelativeTo(null); final StyleContext cont = StyleContext.getDefaultStyleContext(); final AttributeSet attr = cont.addAttribute(cont.getEmptySet(), StyleConstants.Foreground, Color.RED); final AttributeSet attrBlack = cont.addAttribute(cont.getEmptySet(), StyleConstants.Foreground, Color.BLACK); DefaultStyledDocument doc = new DefaultStyledDocument() { public void insertString (int offset, String str, AttributeSet a) throws BadLocationException { super.insertString(offset, str, a); String text = getText(0, getLength()); int before = findLastNonWordChar(text, offset); if (before < 0) before = 0; int after = findFirstNonWordChar(text, offset + str.length()); int wordL = before; int wordR = before; while (wordR <= after) { if (wordR == after || String.valueOf(text.charAt(wordR)).matches("\\W")) { if (text.substring(wordL, wordR).matches("(\\W)*(private|public|protected)")) setCharacterAttributes(wordL, wordR - wordL, attr, false); else setCharacterAttributes(wordL, wordR - wordL, attrBlack, false); wordL = wordR; } wordR++; } } public void remove (int offs, int len) throws BadLocationException { super.remove(offs, len); String text = getText(0, getLength()); int before = findLastNonWordChar(text, offs); if (before < 0) before = 0; int after = findFirstNonWordChar(text, offs); if (text.substring(before, after).matches("(\\W)*(private|public|protected)")) { setCharacterAttributes(before, after - before, attr, false); } else { setCharacterAttributes(before, after - before, attrBlack, false); } } }; JTextPane txt = new JTextPane(doc); txt.setText("public class Hi {}"); add(new JScrollPane(txt)); setVisible(true); } public static void main (String args[]) { new Test(); } } 

代码是不是很漂亮,因为我很快键入它,但它的作品。 我希望这会给你一些提示。

另一个解决scheme是使用DocumentFilter

这里是一个例子:

创build一个扩展DocumentFilter的类:

 private final class CustomDocumentFilter extends DocumentFilter { private final StyledDocument styledDocument = yourTextPane.getStyledDocument(); private final StyleContext styleContext = StyleContext.getDefaultStyleContext(); private final AttributeSet greenAttributeSet = styleContext.addAttribute(styleContext.getEmptySet(), StyleConstants.Foreground, Color.GREEN); private final AttributeSet blackAttributeSet = styleContext.addAttribute(styleContext.getEmptySet(), StyleConstants.Foreground, Color.BLACK); // Use a regular expression to find the words you are looking for Pattern pattern = buildPattern(); @Override public void insertString(FilterBypass fb, int offset, String text, AttributeSet attributeSet) throws BadLocationException { super.insertString(fb, offset, text, attributeSet); handleTextChanged(); } @Override public void remove(FilterBypass fb, int offset, int length) throws BadLocationException { super.remove(fb, offset, length); handleTextChanged(); } @Override public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attributeSet) throws BadLocationException { super.replace(fb, offset, length, text, attributeSet); handleTextChanged(); } /** * Runs your updates later, not during the event notification. */ private void handleTextChanged() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { updateTextStyles(); } }); } /** * Build the regular expression that looks for the whole word of each word that you wish to find. The "\\b" is the beginning or end of a word boundary. The "|" is a regex "or" operator. * @return */ private Pattern buildPattern() { StringBuilder sb = new StringBuilder(); for (String token : ALL_WORDS_THAT_YOU_WANT_TO_FIND) { sb.append("\\b"); // Start of word boundary sb.append(token); sb.append("\\b|"); // End of word boundary and an or for the next word } if (sb.length() > 0) { sb.deleteCharAt(sb.length() - 1); // Remove the trailing "|" } Pattern p = Pattern.compile(sb.toString()); return p; } private void updateTextStyles() { // Clear existing styles styledDocument.setCharacterAttributes(0, yourTextPane.getText().length(), blackAttributeSet, true); // Look for tokens and highlight them Matcher matcher = pattern.matcher(yourTextPane.getText()); while (matcher.find()) { // Change the color of recognized tokens styledDocument.setCharacterAttributes(matcher.start(), matcher.end() - matcher.start(), greenAttributeSet, false); } } } 

您所需要做的就是将您创build的DocumentFilter应用于JTextPane ,如下所示:

 ((AbstractDocument) yourTextPane.getDocument()).setDocumentFilter(new CustomDocumentFilter()); 

您可以扩展DefaultStyledDocument,就像我在这里为一个SQL编辑器,我正在build设关键字文字着色…

  import java.util.ArrayList; import java.util.List; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultStyledDocument; import javax.swing.text.Style; public class KeywordStyledDocument extends DefaultStyledDocument { private static final long serialVersionUID = 1L; private Style _defaultStyle; private Style _cwStyle; public KeywordStyledDocument(Style defaultStyle, Style cwStyle) { _defaultStyle = defaultStyle; _cwStyle = cwStyle; } public void insertString (int offset, String str, AttributeSet a) throws BadLocationException { super.insertString(offset, str, a); refreshDocument(); } public void remove (int offs, int len) throws BadLocationException { super.remove(offs, len); refreshDocument(); } private synchronized void refreshDocument() throws BadLocationException { String text = getText(0, getLength()); final List<HiliteWord> list = processWords(text); setCharacterAttributes(0, text.length(), _defaultStyle, true); for(HiliteWord word : list) { int p0 = word._position; setCharacterAttributes(p0, word._word.length(), _cwStyle, true); } } private static List<HiliteWord> processWords(String content) { content += " "; List<HiliteWord> hiliteWords = new ArrayList<HiliteWord>(); int lastWhitespacePosition = 0; String word = ""; char[] data = content.toCharArray(); for(int index=0; index < data.length; index++) { char ch = data[index]; if(!(Character.isLetter(ch) || Character.isDigit(ch) || ch == '_')) { lastWhitespacePosition = index; if(word.length() > 0) { if(isReservedWord(word)) { hiliteWords.add(new HiliteWord(word,(lastWhitespacePosition - word.length()))); } word=""; } } else { word += ch; } } return hiliteWords; } private static final boolean isReservedWord(String word) { return(word.toUpperCase().trim().equals("CROSS") || word.toUpperCase().trim().equals("CURRENT_DATE") || word.toUpperCase().trim().equals("CURRENT_TIME") || word.toUpperCase().trim().equals("CURRENT_TIMESTAMP") || word.toUpperCase().trim().equals("DISTINCT") || word.toUpperCase().trim().equals("EXCEPT") || word.toUpperCase().trim().equals("EXISTS") || word.toUpperCase().trim().equals("FALSE") || word.toUpperCase().trim().equals("FETCH") || word.toUpperCase().trim().equals("FOR") || word.toUpperCase().trim().equals("FROM") || word.toUpperCase().trim().equals("FULL") || word.toUpperCase().trim().equals("GROUP") || word.toUpperCase().trim().equals("HAVING") || word.toUpperCase().trim().equals("INNER") || word.toUpperCase().trim().equals("INTERSECT") || word.toUpperCase().trim().equals("IS") || word.toUpperCase().trim().equals("JOIN") || word.toUpperCase().trim().equals("LIKE") || word.toUpperCase().trim().equals("LIMIT") || word.toUpperCase().trim().equals("MINUS") || word.toUpperCase().trim().equals("NATURAL") || word.toUpperCase().trim().equals("NOT") || word.toUpperCase().trim().equals("NULL") || word.toUpperCase().trim().equals("OFFSET") || word.toUpperCase().trim().equals("ON") || word.toUpperCase().trim().equals("ORDER") || word.toUpperCase().trim().equals("PRIMARY") || word.toUpperCase().trim().equals("ROWNUM") || word.toUpperCase().trim().equals("SELECT") || word.toUpperCase().trim().equals("SYSDATE") || word.toUpperCase().trim().equals("SYSTIME") || word.toUpperCase().trim().equals("SYSTIMESTAMP") || word.toUpperCase().trim().equals("TODAY") || word.toUpperCase().trim().equals("TRUE") || word.toUpperCase().trim().equals("UNION") || word.toUpperCase().trim().equals("UNIQUE") || word.toUpperCase().trim().equals("WHERE")); } } 

简单地把它添加到你的class级就像这样:

  import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTextPane; import javax.swing.text.BadLocationException; import javax.swing.text.Style; import javax.swing.text.StyleConstants; import javax.swing.text.StyleContext; public class SQLEditor extends JFrame { private static final long serialVersionUID = 1L; public SQLEditor() { StyleContext styleContext = new StyleContext(); Style defaultStyle = styleContext.getStyle(StyleContext.DEFAULT_STYLE); Style cwStyle = styleContext.addStyle("ConstantWidth", null); StyleConstants.setForeground(cwStyle, Color.BLUE); StyleConstants.setBold(cwStyle, true); final JTextPane pane = new JTextPane(new KeywordStyledDocument(defaultStyle, cwStyle)); pane.setFont(new Font("Courier New", Font.PLAIN, 12)); JScrollPane scrollPane = new JScrollPane(pane); getContentPane().add(scrollPane, BorderLayout.CENTER); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(375, 400); } public static void main(String[] args) throws BadLocationException { SQLEditor app = new SQLEditor(); app.setVisible(true); } } 

这里是缺less的HiliteWord类…

 public class HiliteWord { int _position; String _word; public HiliteWord(String word, int position) { _position = position; _word = word; } }