MyException - 我的异常网
当前位置:我的异常网» J2SE » 写自己的文本编辑器(一): 高亮关键字,该如何解决

写自己的文本编辑器(一): 高亮关键字,该如何解决

www.MyException.Cn  网友分享于:2013-01-21  浏览:41次
写自己的文本编辑器(一): 高亮关键字
Java code
写自己的文本编辑器(一): 高亮关键字
一. 高亮的内容:
需要高亮的内容有:
1. 关键字, 如 public, int, true 等. 
2. 运算符, 如 +, -, *, /等
3. 数字
4. 高亮字符串, 如 "example of string"
5. 高亮单行注释
6. 高亮多行注释

二. 实现高亮的核心方法:
StyledDocument.setCharacterAttributes(int offset, int length, AttributeSet s, boolean replace) 

三. 文本编辑器选择.
Java中提供的多行文本编辑器有: JTextComponent, JTextArea, JTextPane, JEditorPane等, 都可以使用. 但是因为语法着色中文本要使用多种风格的样式, 所以这些文本编辑器的document要使用StyledDocument. 
JTextArea使用的是PlainDocument, 此document不能进行多种格式的着色.
JTextPane, JEditorPane使用的是StyledDocument, 默认就可以使用. 
为了实现语法着色, 可以继承自DefaultStyledDocument, 设置其为这些文本编辑器的documet, 或者也可以直接使用JTextPane, JEditorPane来做. 为了方便, 这里就直接使用JTextPane了.

四. 何时进行着色.
当文本编辑器中有字符被插入或者删除时, 文本的内容就发生了变化, 这时检查, 进行着色.
为了监视到文本的内容发生了变化, 要给document添加一个DocumentListener监听器, 在他的removeUpdate和insertUpdate中进行着色处理.
而changedUpdate方法在文本的属性例如前景色, 背景色, 字体等风格改变时才会被调用.
    @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 {
            // 因为删除后光标紧接着影响的单词两边, 所以长度就不需要了
            colouring((StyledDocument) e.getDocument(), e.getOffset(), 0);
        } catch (BadLocationException e1) {
            e1.printStackTrace();
        }
    }

五. 着色范围: 
pos: 指变化前光标的位置.
len: 指变化的字符数.
例如有关键字public, int
单词"publicint", 在"public"和"int"中插入一个空格后变成"public int", 一个单词变成了两个, 这时对"public" 和 "int"进行着色.
着色范围是public中p的位置和int中t的位置加1, 即是pos前面单词开始的下标和pos+len开始单词结束的下标. 所以上例中要着色的范围是"public int". 
提供了方法indexOfWordStart来取得pos前单词开始的下标, 方法indexOfWordEnd来取得pos后单词结束的下标.
    public int indexOfWordStart(Document doc, int pos) throws BadLocationException {
        // 从pos开始向前找到第一个非单词字符.
        for (; pos > 0 && isWordCharacter(doc, pos - 1); --pos);
        return pos;
    }

    public int indexOfWordEnd(Document doc, int pos) throws BadLocationException {
        // 从pos开始向前找到第一个非单词字符.
        for (; isWordCharacter(doc, pos); ++pos);
        return pos;
    }


     一个字符是单词的有效字符: 是字母, 数字, 下划线.
    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);

六. 关键字着色.
从着色范围的开始下标起进行判断, 如果是以字母开或者下划线开头, 则说明是单词, 那么先取得这个单词, 如果这个单词是关键字, 就进行关键字着色, 如果不是, 就进行普通的着色. 着色完这个单词后, 继续后面的着色处理. 已经着色过的字符, 就不再进行着色了.
    public void colouring(StyledDocument doc, int pos, int len) throws BadLocationException {
        // 取得插入或者删除后影响到的单词.
        // 例如"public"在b后插入一个空格, 就变成了:"pub lic", 这时就有两个单词要处理:"pub"和"lic"
        // 这时要取得的范围是pub中p前面的位置和lic中c后面的位置
        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为处理后的最后一个下标
                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); // 要进行着色的单词

        if (keywords.contains(word)) {
            // 如果是关键字, 就进行关键字的着色, 否则使用普通的着色.
            // 这里有一点要注意, 在insertUpdate和removeUpdate的方法调用的过程中, 不能修改doc的属性.
            // 但我们又要达到能够修改doc的属性, 所以把此任务放到这个方法的外面去执行.
            // 实现这一目的, 可以使用新线程, 但放到swing的事件队列里去处理更轻便一点.
            SwingUtilities.invokeLater(new ColouringTask(doc, pos, wordEnd - pos, keywordStyle));
        } else {
            SwingUtilities.invokeLater(new ColouringTask(doc, pos, wordEnd - pos, normalStyle));
        }

        return wordEnd;
    }

因为在insertUpdate和removeUpdate方法中不能修改document的属性, 所以着色的任务放到这两个方法外面, 所以使用了SwingUtilities.invokeLater来实现.
    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 {
                // 这里就是对字符进行着色
                doc.setCharacterAttributes(pos, len, style, true);
            } catch (Exception e) {}
        }
    }

文章评论

程序员应该关注的一些事儿
程序员应该关注的一些事儿
一个程序员的时间管理
一个程序员的时间管理
编程语言是女人
编程语言是女人
 程序员的样子
程序员的样子
中美印日四国程序员比较
中美印日四国程序员比较
程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
我是如何打败拖延症的
我是如何打败拖延症的
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
总结2014中国互联网十大段子
总结2014中国互联网十大段子
程序员必看的十大电影
程序员必看的十大电影
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
如何成为一名黑客
如何成为一名黑客
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
鲜为人知的编程真相
鲜为人知的编程真相
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
程序员和编码员之间的区别
程序员和编码员之间的区别
那些争议最大的编程观点
那些争议最大的编程观点
代码女神横空出世
代码女神横空出世
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
旅行,写作,编程
旅行,写作,编程
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
漫画:程序员的工作
漫画:程序员的工作
程序员都该阅读的书
程序员都该阅读的书
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
10个调试和排错的小建议
10个调试和排错的小建议
每天工作4小时的程序员
每天工作4小时的程序员
我的丈夫是个程序员
我的丈夫是个程序员
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有