• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            逛奔的蝸牛

            我不聰明,但我會很努力

               ::  :: 新隨筆 ::  ::  :: 管理 ::

            寫自己的文本編輯器(): 高亮關(guān)鍵字

            . 高亮的內(nèi)容:

            需要高亮的內(nèi)容有:

            1. 關(guān)鍵字, public, int, true

            2. 運(yùn)算符, +, -, *, /

            3. 數(shù)字

            4. 高亮字符串, "example of string"

            5. 高亮單行注釋

            6. 高亮多行注釋


            . 實(shí)現(xiàn)高亮的核心方法:

            StyledDocument.setCharacterAttributes(int offset, int length, AttributeSet s, boolean replace) 


            . 文本編輯器選擇.

            Java中提供的多行文本編輯器有: JTextComponent, JTextArea, JTextPane, JEditorPane, 都可以使用. 但是因?yàn)檎Z法著色中文本要使用多種風(fēng)格的樣式, 所以這些文本編輯器的document要使用StyledDocument. 

            JTextArea使用的是PlainDocument, document不能進(jìn)行多種格式的著色.

            JTextPane, JEditorPane使用的是StyledDocument, 默認(rèn)就可以使用

            為了實(shí)現(xiàn)語法著色, 可以繼承自DefaultStyledDocument, 設(shè)置其為這些文本編輯器的documet, 或者也可以直接使用JTextPane, JEditorPane來做. 為了方便, 這里就直接使用JTextPane.


            . 何時(shí)進(jìn)行著色.

            當(dāng)文本編輯器中有字符被插入或者刪除時(shí), 文本的內(nèi)容就發(fā)生了變化, 這時(shí)檢查, 進(jìn)行著色.

            為了監(jiān)視到文本的內(nèi)容發(fā)生了變化, 要給document添加一個(gè)DocumentListener監(jiān)聽器, 在他的removeUpdateinsertUpdate中進(jìn)行著色處理.

            changedUpdate方法在文本的屬性例如前景色, 背景色, 字體等風(fēng)格改變時(shí)才會被調(diào)用.

            @Override

            public void changedUpdate(DocumentEvent e) {


            }


            @Override

            public void insertUpdate(DocumentEvent e) {

            try {

            colouring((StyledDocument) e.getDocument(), e.getOffset(), e.getLength());

            } catch (BadLocationException e1) {

            e1.printStackTrace();

            }

            }


            @Override

            public void removeUpdate(DocumentEvent e) {

            try {

            // 因?yàn)閯h除后光標(biāo)緊接著影響的單詞兩邊, 所以長度就不需要了

            colouring((StyledDocument) e.getDocument(), e.getOffset(), 0);

            } catch (BadLocationException e1) {

            e1.printStackTrace();

            }

            }


            . 著色范圍

            pos: 指變化前光標(biāo)的位置.

            len: 指變化的字符數(shù).

            例如有關(guān)鍵字public, int

            單詞"publicint", "public""int"中插入一個(gè)空格后變成"public int", 一個(gè)單詞變成了兩個(gè), 這時(shí)對"public" "int"進(jìn)行著色.

            著色范圍是publicp的位置和intt的位置加1, 即是pos前面單詞開始的下標(biāo)和pos+len開始單詞結(jié)束的下標(biāo). 所以上例中要著色的范圍是"public int". 

            提供了方法indexOfWordStart來取得pos前單詞開始的下標(biāo), 方法indexOfWordEnd來取得pos后單詞結(jié)束的下標(biāo).

            public int indexOfWordStart(Document doc, int pos) throws BadLocationException {

            // pos開始向前找到第一個(gè)非單詞字符.

            for (; pos > 0 && isWordCharacter(doc, pos - 1); --pos);

            return pos;

            }


            public int indexOfWordEnd(Document doc, int pos) throws BadLocationException {

            // pos開始向前找到第一個(gè)非單詞字符.

            for (; isWordCharacter(doc, pos); ++pos);

            return pos;

            }



            一個(gè)字符是單詞的有效字符: 是字母, 數(shù)字, 下劃線.

            public boolean isWordCharacter(Document doc, int pos) throws BadLocationException {

            char ch = getCharAt(doc, pos); // 取得在文檔中pos位置處的字符

            if (Character.isLetter(ch) || Character.isDigit(ch) || ch == '_') { return true; }

            return false;

            }


            所以著色的范圍是[start, end] :

            int start = indexOfWordStart(doc, pos);

            int end = indexOfWordEnd(doc, pos + len);


            . 關(guān)鍵字著色.

            從著色范圍的開始下標(biāo)起進(jìn)行判斷, 如果是以字母開或者下劃線開頭, 則說明是單詞, 那么先取得這個(gè)單詞, 如果這個(gè)單詞是關(guān)鍵字, 就進(jìn)行關(guān)鍵字著色, 如果不是, 就進(jìn)行普通的著色. 著色完這個(gè)單詞后, 繼續(xù)后面的著色處理. 已經(jīng)著色過的字符, 就不再進(jìn)行著色了.

            public void colouring(StyledDocument doc, int pos, int len) throws BadLocationException {

            // 取得插入或者刪除后影響到的單詞.

            // 例如"public"b后插入一個(gè)空格, 就變成了:"pub lic", 這時(shí)就有兩個(gè)單詞要處理:"pub""lic"

            // 這時(shí)要取得的范圍是pubp前面的位置和licc后面的位置

            int start = indexOfWordStart(doc, pos);

            int end = indexOfWordEnd(doc, pos + len);


            char ch;

            while (start < end) {

            ch = getCharAt(doc, start);

            if (Character.isLetter(ch) || ch == '_') {

            // 如果是以字母或者下劃線開頭, 說明是單詞

            // pos為處理后的最后一個(gè)下標(biāo)

            start = colouringWord(doc, start);

            } else {

            //SwingUtilities.invokeLater(new ColouringTask(doc, pos, wordEnd - pos, normalStyle));

            ++start;

            }

            }

            }



            public int colouringWord(StyledDocument doc, int pos) throws BadLocationException {

            int wordEnd = indexOfWordEnd(doc, pos);

            String word = doc.getText(pos, wordEnd - pos); // 要進(jìn)行著色的單詞


            if (keywords.contains(word)) {

            // 如果是關(guān)鍵字, 就進(jìn)行關(guān)鍵字的著色, 否則使用普通的著色.

            // 這里有一點(diǎn)要注意, insertUpdateremoveUpdate的方法調(diào)用的過程中, 不能修改doc的屬性.

            // 但我們又要達(dá)到能夠修改doc的屬性, 所以把此任務(wù)放到這個(gè)方法的外面去執(zhí)行.

            // 實(shí)現(xiàn)這一目的, 可以使用新線程, 但放到swing的事件隊(duì)列里去處理更輕便一點(diǎn).

            SwingUtilities.invokeLater(new ColouringTask(doc, pos, wordEnd - pos, keywordStyle));

            } else {

            SwingUtilities.invokeLater(new ColouringTask(doc, pos, wordEnd - pos, normalStyle));

            }


            return wordEnd;

            }


            因?yàn)樵?/span>insertUpdateremoveUpdate方法中不能修改document的屬性, 所以著色的任務(wù)放到這兩個(gè)方法外面, 所以使用了SwingUtilities.invokeLater來實(shí)現(xiàn).

            private class ColouringTask implements Runnable {

            private StyledDocument doc;

            private Style style;

            private int pos;

            private int len;


            public ColouringTask(StyledDocument doc, int pos, int len, Style style) {

            this.doc = doc;

            this.pos = pos;

            this.len = len;

            this.style = style;

            }


            public void run() {

            try {

            // 這里就是對字符進(jìn)行著色

            doc.setCharacterAttributes(pos, len, style, true);

            } catch (Exception e) {}

            }

            }



            : 源碼

            關(guān)鍵字著色的完成代碼如下, 可以直接編譯運(yùn)行. 對于數(shù)字, 運(yùn)算符, 字符串等的著色處理在以后的教程中會繼續(xù)進(jìn)行詳解.

            import java.awt.Color;

            import java.util.HashSet;

            import java.util.Set;


            import javax.swing.JFrame;

            import javax.swing.JTextPane;

            import javax.swing.SwingUtilities;

            import javax.swing.event.DocumentEvent;

            import javax.swing.event.DocumentListener;

            import javax.swing.text.BadLocationException;

            import javax.swing.text.Document;

            import javax.swing.text.Style;

            import javax.swing.text.StyleConstants;

            import javax.swing.text.StyledDocument;


            public class HighlightKeywordsDemo {

            public static void main(String[] args) {

            JFrame frame = new JFrame();


            JTextPane editor = new JTextPane();

            editor.getDocument().addDocumentListener(new SyntaxHighlighter(editor));

            frame.getContentPane().add(editor);


            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            frame.setSize(500, 500);

            frame.setVisible(true);

            }

            }


            /**

             * 當(dāng)文本輸入?yún)^(qū)的有字符插入或者刪除時(shí), 進(jìn)行高亮.

             * 

             * 要進(jìn)行語法高亮, 文本輸入組件的document要是styled document才行. 所以不要用JTextArea. 可以使用JTextPane.

             * 

             * @author Biao

             * 

             */

            class SyntaxHighlighter implements DocumentListener {

            private Set<String> keywords;

            private Style keywordStyle;

            private Style normalStyle;


            public SyntaxHighlighter(JTextPane editor) {

            // 準(zhǔn)備著色使用的樣式

            keywordStyle = ((StyledDocument) editor.getDocument()).addStyle("Keyword_Style", null);

            normalStyle = ((StyledDocument) editor.getDocument()).addStyle("Keyword_Style", null);

            StyleConstants.setForeground(keywordStyle, Color.RED);

            StyleConstants.setForeground(normalStyle, Color.BLACK);


            // 準(zhǔn)備關(guān)鍵字

            keywords = new HashSet<String>();

            keywords.add("public");

            keywords.add("protected");

            keywords.add("private");

            keywords.add("_int9");

            keywords.add("float");

            keywords.add("double");

            }


            public void colouring(StyledDocument doc, int pos, int len) throws BadLocationException {

            // 取得插入或者刪除后影響到的單詞.

            // 例如"public"b后插入一個(gè)空格, 就變成了:"pub lic", 這時(shí)就有兩個(gè)單詞要處理:"pub""lic"

            // 這時(shí)要取得的范圍是pubp前面的位置和licc后面的位置

            int start = indexOfWordStart(doc, pos);

            int end = indexOfWordEnd(doc, pos + len);


            char ch;

            while (start < end) {

            ch = getCharAt(doc, start);

            if (Character.isLetter(ch) || ch == '_') {

            // 如果是以字母或者下劃線開頭, 說明是單詞

            // pos為處理后的最后一個(gè)下標(biāo)

            start = colouringWord(doc, start);

            } else {

            SwingUtilities.invokeLater(new ColouringTask(doc, start, 1, normalStyle));

            ++start;

            }

            }

            }


            /**

            * 對單詞進(jìn)行著色, 并返回單詞結(jié)束的下標(biāo).

            * @param doc

            * @param pos

            * @return

            * @throws BadLocationException

            */

            public int colouringWord(StyledDocument doc, int pos) throws BadLocationException {

            int wordEnd = indexOfWordEnd(doc, pos);

            String word = doc.getText(pos, wordEnd - pos);


            if (keywords.contains(word)) {

            // 如果是關(guān)鍵字, 就進(jìn)行關(guān)鍵字的著色, 否則使用普通的著色.

            // 這里有一點(diǎn)要注意, insertUpdateremoveUpdate的方法調(diào)用的過程中, 不能修改doc的屬性.

            // 但我們又要達(dá)到能夠修改doc的屬性, 所以把此任務(wù)放到這個(gè)方法的外面去執(zhí)行.

            // 實(shí)現(xiàn)這一目的, 可以使用新線程, 但放到swing的事件隊(duì)列里去處理更輕便一點(diǎn).

            SwingUtilities.invokeLater(new ColouringTask(doc, pos, wordEnd - pos, keywordStyle));

            } else {

            SwingUtilities.invokeLater(new ColouringTask(doc, pos, wordEnd - pos, normalStyle));

            }


            return wordEnd;

            }


            /**

            * 取得在文檔中下標(biāo)在pos處的字符.

            * 如果posdoc.getLength(), 返回的是一個(gè)文檔的結(jié)束符, 不會拋出異常. 如果pos<0, 則會拋出異常.

            * 所以pos的有效值是[0, doc.getLength()]

            * @param doc

            * @param pos

            * @return

            * @throws BadLocationException

            */

            public char getCharAt(Document doc, int pos) throws BadLocationException {

            return doc.getText(pos, 1).charAt(0);

            }


            /**

            * 取得下標(biāo)為pos時(shí), 它所在的單詞開始的下標(biāo). ±wor^d± (^表示pos, ±表示開始或結(jié)束的下標(biāo))

            * @param doc

            * @param pos

            * @return

            * @throws BadLocationException

            */

            public int indexOfWordStart(Document doc, int pos) throws BadLocationException {

            // pos開始向前找到第一個(gè)非單詞字符.

            for (; pos > 0 && isWordCharacter(doc, pos - 1); --pos);


            return pos;

            }


            /**

            * 取得下標(biāo)為pos時(shí), 它所在的單詞結(jié)束的下標(biāo). ±wor^d± (^表示pos, ±表示開始或結(jié)束的下標(biāo))

            * @param doc

            * @param pos

            * @return

            * @throws BadLocationException

            */

            public int indexOfWordEnd(Document doc, int pos) throws BadLocationException {

            // pos開始向前找到第一個(gè)非單詞字符.

            for (; isWordCharacter(doc, pos); ++pos);


            return pos;

            }


            /**

            * 如果一個(gè)字符是字母, 數(shù)字, 下劃線, 則返回true.

            * @param doc

            * @param pos

            * @return

            * @throws BadLocationException

            */

            public boolean isWordCharacter(Document doc, int pos) throws BadLocationException {

            char ch = getCharAt(doc, pos);

            if (Character.isLetter(ch) || Character.isDigit(ch) || ch == '_') { return true; }

            return false;

            }


            @Override

            public void changedUpdate(DocumentEvent e) {


            }


            @Override

            public void insertUpdate(DocumentEvent e) {

            try {

            colouring((StyledDocument) e.getDocument(), e.getOffset(), e.getLength());

            } catch (BadLocationException e1) {

            e1.printStackTrace();

            }

            }


            @Override

            public void removeUpdate(DocumentEvent e) {

            try {

            // 因?yàn)閯h除后光標(biāo)緊接著影響的單詞兩邊, 所以長度就不需要了

            colouring((StyledDocument) e.getDocument(), e.getOffset(), 0);

            } catch (BadLocationException e1) {

            e1.printStackTrace();

            }

            }


            /**

            * 完成著色任務(wù)

            * @author Biao

            */

            private class ColouringTask implements Runnable {

            private StyledDocument doc;

            private Style style;

            private int pos;

            private int len;


            public ColouringTask(StyledDocument doc, int pos, int len, Style style) {

            this.doc = doc;

            this.pos = pos;

            this.len = len;

            this.style = style;

            }


            public void run() {

            try {

            // 這里就是對字符進(jìn)行著色

            doc.setCharacterAttributes(pos, len, style, true);

            } catch (Exception e) {}

            }

            }

            }

            posted on 2010-02-05 19:00 逛奔的蝸牛 閱讀(9203) 評論(0)  編輯 收藏 引用 所屬分類: Java
            国产精品久久久香蕉| 国产精品久久久久aaaa| 亚洲精品无码专区久久同性男| 久久精品视频免费| 无码任你躁久久久久久老妇| 亚洲精品午夜国产VA久久成人| 俺来也俺去啦久久综合网| 久久国产免费| 久久AV高清无码| 日本国产精品久久| 97久久综合精品久久久综合| 武侠古典久久婷婷狼人伊人| 久久w5ww成w人免费| 日本加勒比久久精品| 91精品国产91久久久久福利| 久久五月精品中文字幕| 国产Av激情久久无码天堂| 久久久无码精品午夜| www久久久天天com| 久久精品一区二区三区AV| 国产高潮国产高潮久久久91| 久久久久久久人妻无码中文字幕爆| 国产精品热久久毛片| 国产成人久久精品一区二区三区| 亚洲精品无码专区久久久| 尹人香蕉久久99天天拍| 日韩va亚洲va欧美va久久| 久久996热精品xxxx| 国产精自产拍久久久久久蜜| 久久精品免费一区二区三区| 久久婷婷五月综合国产尤物app| 一本色道久久88综合日韩精品 | 蜜臀久久99精品久久久久久小说| 青青草国产97免久久费观看| 久久精品中文字幕一区| 久久久久国产视频电影| 久久成人国产精品一区二区| 中文字幕成人精品久久不卡| 91久久成人免费| 青青青青久久精品国产h久久精品五福影院1421 | 婷婷五月深深久久精品|