zoukankan      html  css  js  c++  java
  • Swing实现Java代码编辑器实现关键词高亮显示

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



        

        当JEditorPane被创建时,它会把createDefaultEditorKit()方法(javax.swing.text.EditorKit的子类对象)的返回值作为默认的编辑器工具包,然后将文本的编辑与显示工作交给这个工具包。其原型为:


    Java代码
    1. protected EditorKit createDefaultEditorKit()  
    2. {  
    3.     return new PlainEditorKit();  
    4. }  
    protected EditorKit createDefaultEditorKit()
    {
        return new PlainEditorKit();
    }
    
     

        这个方法默认是返回一个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类很简单:

    Java代码
    1. public 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. }  
    public class JavaViewFactory implements ViewFactory
    {
        /**//*
         * (non-Javadoc)
         * 
         * @see javax.swing.text.ViewFactory#create(javax.swing.text.Element)
         */
        public View create(Element element)
        {
            return new JavaEditorView(element);
        }
    }

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

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


    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

    下面是覆盖后的实现:

    Java代码
    1. protected 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. }  
    protected int drawUnselectedText(Graphics g, int x, int y, int startOffset, int endOffset)
        throws BadLocationException
    {
        int docLength = getDocument().getLength();
        int length = (endOffset < docLength ? endOffset : docLength) - startOffset;
    
        return scanParagraph(g, x, y, startOffset, length);
    }
     

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

    private int scanParagraph(Graphics g, int x, int y, int startOffset, int length) throws BadLocationException
    {
        Segment seg = new Segment();
        //得到编辑器组件
        JavaCodeEditor editor = (JavaCodeEditor) getContainer();
        //得到startOffset,位置开始的length个长度的字符串,其实也就是我们要处理的字符串
        getDocument().getText(startOffset, length, seg);
        for (int wordIndex = 0; wordIndex < seg.length();)
        {
            char currentChar = seg.charAt(wordIndex);
            if (Character.isJavaIdentifierStart(currentChar))
            {
                //下面我默认用Object说明,实际中要处理seg中的内容。
                String identifier = "Object";
                int len = identifier.length();

                //比如说以红色显示类名
                Segment text = getLineBuffer();
                getDocument().getText(startOffset + wordIndex, len, text);
                //还有其它样式的话只管给g加
                g.setColor(color);

                Utilities.drawTabbedText(text, x, y, g, this, startOffset + wordIndex);
               
                //下面的代码略
                .
            }
        }
        //下面的代码略
        .
    }

    
  • 相关阅读:
    -bash: fork: Cannot allocate memory 问题的处理
    Docker top 命令
    docker常见问题修复方法
    The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
    What's the difference between encoding and charset?
    hexcode of é î Latin-1 Supplement
    炉石Advanced rulebook
    炉石bug反馈
    Sidecar pattern
    SQL JOIN
  • 原文地址:https://www.cnblogs.com/jishu/p/1959896.html
Copyright © 2011-2022 走看看