• [整理]如何做一个语法着色控件


    前言

    很多IDE或者开发工具中都有语法着色的功能,这是如何实现的呢?笔者试着用C#做了一个Sample,基本上实现此功能。
    本文一半是原创,一半是参考国外的论坛

    思路

    语法着色器,实际上只做了两件事情:“接受用户输入”以及“改变关键字字体属性”。

    1)首先看第一个:接受用户输入。

    C#自带的控件中能够满足需求的首推“RichTextBox”,笔者在网上经常看到很多同行都以此为基础,制作出类似MS-Word的种种效果。既然,复杂的Word效果都能够实现,那么语法着色自然也就不在话下。

    2)其次,最重要的“改变关键字字体属性”。

    这一点还可分成三个更小的工作:关键字列表、判断关键字、定义字体属性。
  • 关键字列表很简单,一个List即可满足需求。
    这里以基本SQL语句为例。
    private IList<String> _KeyWords = new List<String>()
    {
        "SELECT", "UPDATE", "DELETE", "INSERT", "DROP", "FROM", "WHERE", "ALERT", "CREATE", "TABLE",
        "VALUES", "NULL",
        "AND", "OR", "NOT", "IN", "INTO", "UNION", "AS", "IS",
        "COUNT", "MAX", "MIN", "AVG",
        "WAIT", "NOWAIT", "WITHOUT", "LOCK", "GROUP", "ORDER", "BY",
        "JOIN", "LEFT", "RIGHT", "CASE", "WHEN", "ELSE", "END",
        "COMMIT", "ROLLBACK"
    };
  • 判断关键字
    为了在用户输入时能够立即对所输入的内容有所反映,我们需要override一下RichTextBox的OnTextChanged()方法。
    其他属性及方法介绍请参考MSDN
    笔者的算法很简单,遍历业已定义好的关键字列表,用其与用户输入的内容进行比较,如果发现相同,则按照字符的index值计算编辑区域。
  • 定义字体属性
    在C#中有一个叫做FONT的类能够满足需求。 其他属性及方法介绍请参考MSDN

    注意事项

    笔者在尝试的过程中发现屏幕中显示的内容会随着用户的输入,出现闪烁。究其原因可能是因为Windows一直在重新绘制窗口造成的,为了回避这个问题,我们可以使用SuspendLayout()和ResumeLayout()暂停和恢复画面重新绘制的过程。

    做完这几步,我们的语法着色控件也就大功告成了。下面是全部源代码。在VS2008 Express版本上调试通过。
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Text.RegularExpressions;
    using System.Drawing;
    using System.ComponentModel;
    
    namespace Base
    {
        public partial class SQLEditor : RichTextBox
        {
            
            /// <summary>
            /// 关键字列表
            /// </summary>
            private IList<String> _KeyWords = new List<String>()
            {
                "SELECT", "UPDATE", "DELETE", "INSERT", "DROP", "FROM", "WHERE", "ALERT", "CREATE", "TABLE",
                "VALUES", "NULL",
                "AND", "OR", "NOT", "IN", "INTO", "UNION", "AS", "IS",
                "COUNT", "MAX", "MIN", "AVG",
                "WAIT", "NOWAIT", "WITHOUT", "LOCK", "GROUP", "ORDER", "BY",
                "JOIN", "LEFT", "RIGHT", "CASE", "WHEN", "ELSE", "END",
                "COMMIT", "ROLLBACK"
            };
            [CategoryAttribute("KeyWords"), Description("关键字列表")]
            public IList<String> KeyWords
            {
                get
                {
                    return this._KeyWords;
                }
                set
                {
                    this._KeyWords = value;
                }
            }
    
            /// <summary>
            /// 关键字颜色(默认为蓝色)
            /// </summary>
            private Color _KeyWordsColor = Color.Blue;
            [CategoryAttribute("KeyWordsColor"), Description("关键字颜色")]
            public Color KeyWordsColor
            {
                get
                {
                    return this._KeyWordsColor;
                }
                set
                {
                    this._KeyWordsColor = value;
                }
            }
    
            // TODO 数字,字符串属性
    
            /// <summary>
            /// 分隔符
            /// </summary>
            Regex tokens = new Regex(@"[\s\r\n\t\(\)\;]");
    
            /// <summary>
            /// 接受输入时语法着色
            /// </summary>
            /// <param name="e"></param>
            protected override void OnTextChanged(EventArgs e)
            {
                base.OnTextChanged(e);
    
                // TODO DEBUG
                Console.WriteLine("POINT:" + this.SelectionStart + "|" + "SIZE:" + this.Text.Length);
    
                // 暂停屏幕刷新,防止闪烁
                SuspendLayout();
    
                // 缓存输入焦点位置
                int inputPoint = this.SelectionStart;
    
                String[] wrk_words = tokens.Split(this.Text.ToUpper());
    
                // 判断是否有必要进行着色
                if (this.Text.Length == 0) return;
    
                // 克隆关键字列表
                IList<String> C_KeyWords = new List<String>(this._KeyWords);
                // 关键字开始坐标
                int iStart = 0;
    
                // 初始化
                this.SelectionStart = 0;
                this.SelectionLength = this.Text.Length;
                this.SelectionColor = Color.Black;
                this.SelectionFont = new Font("Courier New", 10, FontStyle.Regular);
    
                // 逐字匹配
                foreach (String word in wrk_words)
                {
                    foreach (String keyw in C_KeyWords)
                    {
                        // 判断当前值是否为关键字
                        if (word.Equals(keyw))
                        {
                            // 查找坐标
                            iStart = this.Text.ToUpper().IndexOf(keyw);
    
                            // 判断是否存在处理对象
                            while (iStart >= 0)
                            {
                                this.SelectionStart = iStart;
                                this.SelectionLength = keyw.Length;
    
                                this.SelectionColor = Color.Blue;
                                this.SelectionFont = new Font("Courier New", 10, FontStyle.Bold);
    
                                // 获取下一次处理开始坐标
                                iStart = this.Text.ToUpper().IndexOf(keyw, this.SelectionStart + 1);
    
                                this.SelectionStart = this.Text.Length;
                                this.SelectionLength = 0;
                            }
                        }
                        // break;
    
                    }
    
                }
    
                // 计算输入点的位置,如果不在末尾,则说明用户在修改前面的内容,否则将焦点移到末尾
                this.SelectionStart = (inputPoint < this.Text.Length) ? inputPoint : this.Text.Length;
                this.SelectionLength = 0;
    
                ResumeLayout();
            }
        }
    }
    
  • 相关阅读:
    android 网络 post get
    java 命名规范
    android 判断service是否开启
    android 无线连接eclipse
    eclipse jar java.lang.NoClassDefFoundError
    eclipse 默认 utf8
    timer timetask handler
    android 自定义动画按钮
    设计网站
    java 分解arraylist中单个对象 的属性名与值
  • 原文地址:https://www.cnblogs.com/hexin0614/p/2324224.html
  • Copyright © 2020-2023  润新知