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

前言

很多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();         }     } }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏儿童编程

什么样的人生才是有意义的人生——没有标准的标准答案

【导读】其实我们可以跳出这个小圈圈去更加科客观地看一下这个世界。在夜晚的时候我们仰望天空,浩瀚的宇宙中整个地球只是一粒浮尘,何况地球上一个小小的人类?在漫长的历...

1.8K50
来自专栏haifeiWu与他朋友们的专栏

复杂业务下向Mysql导入30万条数据代码优化的踩坑记录

从毕业到现在第一次接触到超过30万条数据导入MySQL的场景(有点low),就是在顺丰公司接入我司EMM产品时需要将AD中的员工数据导入MySQL中,因此楼主负...

30540
来自专栏儿童编程

儿童创造力教育与编程教育的碰撞——MIT雷斯尼克教授最新理论梗概

儿童编程教育已经在我国各一线二线城市疯狂出现,颇有“烂大街”的趋势。我们不禁要问很多很多问题:

22670
来自专栏儿童编程

《动物魔法学校》儿童学编程Scratch之“外观”部分

导读:本文通过一个案例《动物魔法学校》来学习Scratch语言的“外观”部分。之后通过一系列其他功能的综合运用对作品功能进行了扩展。

19340
来自专栏儿童编程

一张图理清《梅花易数》梗概

学《易经》的目的不一定是为了卜卦,但是了解卜卦绝对能够让你更好地了解易学。今天用一张思维导图对《梅花易数》的主要内容进行概括,希望能够给学友们提供帮助。

32440
来自专栏儿童编程

声音功能让儿童编程更有创造性

导读:Scratch中声音功能非常强大,除了常规的音效,你甚至可以模拟各种乐器的各个发音、设置节拍、休止……如果你愿意,甚至可以用它创作一个交响乐。我们可以引导...

13940
来自专栏儿童编程

天干地支五行八卦的对应关系

19790
来自专栏Ken的杂谈

【系统设置】CentOS 修改机器名

18430
来自专栏FSociety

SQL中GROUP BY用法示例

GROUP BY我们可以先从字面上来理解,GROUP表示分组,BY后面写字段名,就表示根据哪个字段进行分组,如果有用Excel比较多的话,GROUP BY比较类...

5.2K20
来自专栏儿童编程

我不是算命先生,却对占卜有了疑惑——如何论证“占卜前提”的正确与否

事出有因,我对《周易》感兴趣了很多年。只是觉得特别有趣,断断续续学习了一些皮毛。这几天又偶然接触到了《梅花易数》,觉得很是精彩,将五行八卦天干地支都串联了起来。...

15610

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励