How to change the color of specific words in a JTextPane?

前端 未结 4 1225
醉酒成梦
醉酒成梦 2020-11-28 07:54

How do I change the color of specific words in a JTextPane just while the user is typing? Should I override JTextPane paintComponent m

4条回答
  •  一向
    一向 (楼主)
    2020-11-28 07:59

    Another solution is to use a DocumentFilter.

    Here is an example:

    Create a class that extends 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);
            }
        }
    }
    

    All you need to do then is apply the DocumentFilter that you created to your JTextPane as follows:

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

提交回复
热议问题