随笔 - 4, 文章 - 1, 评论 - 22, 引用 - 0
数据加载中……

Swing实现Java代码编辑器 - 语法高亮显示

    本文主要记录怎么给代码编辑器实际语法高亮显示的功能,先来张效果图吧:
    
    

    当JEditorPane被创建时,它会把createDefaultEditorKit()方法(javax.swing.text.EditorKit的子类对象)的返回值作为默认的编辑器工具包,然后将文本的编辑与显示工作交给这个工具包。其原型为:
1protected EditorKit createDefaultEditorKit()
2{
3    return new PlainEditorKit();
4}
    这个方法默认是返回一个PlainEditorKit对象,也就是一个纯文本的编辑器工具包,所以JEditorPane默认并没有格式化与彩色显示等功能,看来我们先要定制一个支持彩色显示的EditorKit,然后把它作为createDefaultEditorKit()的返回值。

EditorKit基本上什么也没有做,只是提供了很多抽象方法给它的子类去实现,Swing默认已经给它添加了一个子类DefaultEditorKit(Swing常用的一招,就是给抽象类前面加个Default进行最基本的实现),既然是Default,那它所提供的功能肯定和一个记事本没有多大区别,这要是继承下来,有多少方法需要覆盖啊,别慌,查看一下Swing的源码,你会发现Swing还提供了一个继承自DefaultEditorKit的类StyledEditorKit,顾名思义,这个类肯定为我们提供了很多支持格式化显示的方法,又是一个巨人,快,赶紧拉过来往肩上爬。
    接下来就是覆盖StyledEditorKit中的相关方法了,其实有很多方法都可以覆盖,但是意义不是很大,比如
public String getContentType();
    这个方法是获得此工具包声明支持的数据的 MIME 类型,默认是text/plain,也就是文本文档,Java文件说白了也是文本文档,不过可以让它返回 text/java 以唯一标识编辑器所支持的MIME类型。

EditorKit中有两个重要的方法实现对文档的管理与显示:

public abstract Document createDefaultDocument();

创建一个适合此编辑器类型文本存储模型。EditorKit把对文本文档的管理功能交给了这个方法的返回值。

public abstract ViewFactory getViewFactory();

获取适合生成此工具包生成的任何模型视图的工厂。EditorKit把编辑器的显示功能交给了这个方法的返回值,比如什么字符显示成什么样子,什么颜色等。我们必须覆盖这两个方法以实现自定义编辑器的功能。

因为我们的编辑器和JEditorPane唯一不同的可能就是代码怎么来显示,所以createDefaultDocument()可以返回一个默认的javax.swing.text.DefaultStyledDocument 就行,对于getViewFactory,我们需要定制一个ViewFactory视图来实现编辑器独有的各种显示功能。

ViewFactory在Java中被定义为一个接口,里面提供了唯一的一个方法:

public View create(Element elem);

这个方法根据给定的文档的结构化元素创建一个视图。在这个方法中,我们只需要返回一个继承自View的视图即可,真正的显示任务是交给这个视图的。因此,我们的ViewFactory类很简单:

 1public class JavaViewFactory implements ViewFactory
 2{
 3    /*
 4     * (non-Javadoc)
 5     * 
 6     * @see javax.swing.text.ViewFactory#create(javax.swing.text.Element)
 7     */

 8    public View create(Element element)
 9    {
10        return new JavaEditorView(element);
11    }

12}

 

接下来的重点就是这个JavaEditorView了,所有的语法高亮等显示功能都是交给它来完成的

View是一个抽象类,Swing默认给我们提供了多个它的子类,AsyncBoxView, ComponentView, CompositeView, GlyphView, IconView, ImageView, PlainView 以实现对不同文档类型的显示,当中只有PlainView是与文本文档相关的,它实现简单的多行文本视图的 View 接口,该文本视图的文本只有一种字体和颜色,没错,我们的JavaEditorView需要继承自PlainView。

PlainView提供了很多方法进行文本文档的视图显示,要实现高亮显示,我们关心的有两个方法:

protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1) throws BadLocationException

一看名字就知道这个方法是控制选中状态下的显示方式,由于本文只讨论非选中状态。所以重点看一下另外一个方法:

protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1) throws BadLocationException

这个方法将模型中给定的范围呈现为正常的未选定文本。使用前景色或指定的颜色显示文本。

参数:
g  - 图形上下文(做Swing的人再熟悉不过了,文本也是画出来的)
x  - 起始 X 坐标,该值 >= 0
y  - 起始 Y 坐标,该值 >= 0
p0 - 模型中的起始位置,该值 >= 0
p1 - 模型中的结束位置,该值 >= 0

下面是覆盖后的实现:

1protected int drawUnselectedText(Graphics g, int x, int y, int startOffset, int endOffset)
2    throws BadLocationException
3{
4    int docLength = getDocument().getLength();
5    int length = (endOffset < docLength ? endOffset : docLength) - startOffset;
6
7    return scanParagraph(g, x, y, startOffset, length);
8}

先是得到从起始位置到结束位置的长度,然后再交由scanParagraph去处理指定长度的文本,其实也就是怎么把它画出来。
对于一个Java代码编辑器,要考虑类名,运算符,数字,关键字等的显示方式,所以scanParagraph要做的事情很多,本文只以怎么么高亮显示类名为例来说明:

 1private int scanParagraph(Graphics g, int x, int y, int startOffset, int length) throws BadLocationException
 2{
 3    Segment seg = new Segment();
 4    //得到编辑器组件
 5    JavaCodeEditor editor = (JavaCodeEditor) getContainer();
 6    //得到startOffset,位置开始的length个长度的字符串,其实也就是我们要处理的字符串
 7    getDocument().getText(startOffset, length, seg);
 8    for (int wordIndex = 0; wordIndex < seg.length();)
 9    {
10        char currentChar = seg.charAt(wordIndex);
11        if (Character.isJavaIdentifierStart(currentChar))
12        {
13            //下面我默认用Object说明,实际中要处理seg中的内容。
14            String identifier = "Object";
15            int len = identifier.length();
16
17            //比如说以红色显示类名
18            Segment text = getLineBuffer();
19            getDocument().getText(startOffset + wordIndex, len, text);
20            //还有其它样式的话只管给g加
21            g.setColor(color);
22
23            Utilities.drawTabbedText(text, x, y, g, this, startOffset + wordIndex);
24            
25            //下面的代码略
26            .
27        }

28    }

29    //下面的代码略
30    .
31}

我只是以类名进行示范,实际中可能还要考虑此类名是否在注释当中等等...

posted on 2010-02-10 14:27 凯子 阅读(2998) 评论(9)  编辑  收藏 所属分类: Swing

评论

# re: Swing实现Java代码编辑器 - 语法高亮显示  回复  更多评论   

很好
2010-05-06 11:02 | 匿名

# re: Swing实现Java代码编辑器 - 语法高亮显示  回复  更多评论   

能把你写的代码编辑器发给我学习一下吗?lysimon@163.com,thanks。
2010-07-06 21:53 | Simon.C

# re: Swing实现Java代码编辑器 - 语法高亮显示[未登录]  回复  更多评论   

为啥米不讲仔细一点,比如提拱一下源代码
2010-09-18 10:48 | qing

# re: Swing实现Java代码编辑器 - 语法高亮显示  回复  更多评论   

你好,能否将这个JavaCodeEditor的源码发给我来全面的学习一下?万分感谢! waldsteinstay@msn.com
2010-11-28 09:57 | Waldstein

# re: Swing实现Java代码编辑器 - 语法高亮显示  回复  更多评论   

能把你写的代码编辑器发给我学习一下吗?964952294@qq.com
2012-05-03 00:32 | zhu_1989

# re: Swing实现Java代码编辑器 - 语法高亮显示  回复  更多评论   

能不能发下源代码?827972471@qq.com
2012-11-28 22:34 | sunly

# re: Swing实现Java代码编辑器 - 语法高亮显示  回复  更多评论   

你好!能不能发下源代码?whboy803@163.com,感谢!
2013-05-18 18:34 | whboy

# re: Swing实现Java代码编辑器 - 语法高亮显示  回复  更多评论   

同求源码
2015-03-06 16:09 | jycggyh

# re: Swing实现Java代码编辑器 - 语法高亮显示  回复  更多评论   

非常渴望能够获得源代码,liudsnudt@126.com
2015-11-24 19:23 | 刘德生

只有注册用户登录后才能发表评论。


网站导航: