Cómo cambiar el color de las palabras específicas en un JTextPane?

¿Cómo puedo cambiar el color de las palabras específicas en un JTextPane sólo mientras el usuario está escribiendo?
Debo reemplazar JTextPane paintComponent método?

InformationsquelleAutor Soheil | 2013-01-18

4 Kommentare

  1. 14

    Sobrescribir paintComponent no le ayudará.

    Esto no es fácil, pero no imposible. Algo como esto le ayudará a:

    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);

    Usted puede necesitar ajustar esto, pero al menos lo que muestra por dónde empezar.

    • ahora permítame hacerle otra pequeña pregunta aquí, es posible hacer un JTextPane con sólo 1 fila? como un JTextField
  2. 32

    No. No se debe reemplazar el paintComponent() método. En su lugar, debe utilizar StyledDocument. Usted también debe delimitar las palabras por su cuenta propia.

    Aquí es la demo, que convierte a «público», «protegidos» y «lo privado» rojo al escribir, al igual que un simple editor de código:

    Cómo cambiar el color de las palabras específicas en un JTextPane?

    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();
        }
    }

    El código no es tan bella desde que escribí rápidamente, pero funciona. Y espero que le dará alguna pista.

    • ¿Hay alguna otra manera de hacer lo mismo sin el bucle?
    • ¿Te refieres a los bucles en findLastNonWordChar y findFirstNonWordChar? Sí, usted puede encontrar el primer no carácter de palabra sin bucle, ver la respuesta aquí, pero no hay una manera directa para encontrar el último índice de’ no-carácter de palabra. Usted puede intentar usar split() método.
    • Estoy tratando de lo mismo utilizando DocumentListener(), pero tengo una excepción «Intento de mutar en la notificación». ¿Cómo puedo lograr esto mediante DocumentListener().
    • escucha no es la misma cosa aquí. Todos los métodos de DocumentListener se activan después de la actualización es a suceder.
    • Gracias por explicar.
    • ¿sabe usted si hay una posibilidad de que el color de texto en JTextPane ?
    • Sí, pero sólo se puede establecer con el mismo color (el mismo estilo, incluido el tamaño de fuente, tipo de letra, negrita, cursiva, etc.) a todos los personajes en JTextPane.
    • muy útil e interesante

  3. 9

    Otra solución es utilizar un DocumentFilter.

    Aquí está un ejemplo:

    Crear una clase que extienda 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);
            }
        }
    }

    Todo lo que necesitas hacer es aplicar la DocumentFilter que creó a su JTextPane de la siguiente manera:

    ((AbstractDocument) yourTextPane.getDocument()).setDocumentFilter(new CustomDocumentFilter());
    • Esta respuesta se merece más le gusta! Funciona a la perfección para mí, mientras que las otras respuestas son más confuso de utilizar.
    • Desde el DocumentFilter en realidad no hace ningún tipo de filtro, probablemente tiene más sentido utilizar un DocumentListener en su lugar.
  4. 3

    Puede ampliar DefaultStyledDocument como yo lo hice aquí para un editor de SQL, estoy construyendo con el texto de la palabra clave para colorear …

        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"));
            }
        }

    Sólo tiene que añadir a su clase así:

        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);
            }
        }

    Aquí está la falta HiliteWord clase …

    public class HiliteWord {
    
        int _position;  
        String _word;
    
        public HiliteWord(String word, int position) {
            _position = position;   
            _word = word;
        }
    }
    • Donde es la clase HiliteWord?
    • proporcionar el código para HiliteWord clase
    • Lo intenté, pero fue rechazado por 3 de 4 revisores, lo siento

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea