继承RichTextBox,完成代码编辑器,支持语法高亮、行号显示;

 

    最近做一个小工具,需要写SQL脚本,可textbox和richtextbox一片黑色,对于习惯了vs的环境,实在是太惨了点。

于是产生了做一个textbox的想法。

 

    在网上搜了一下,关于继承richtextbox的文章比较多(文章重载的太多),基本上结论就是行号搞不定。

    网上有个ICSharpCode的代码,是外国人写的,非常强,直接在control上绘制文字,不过那源码看起来就恼火了,基本没注释;看了半个晚上,没成绩,留着以后有心情了再看。

 

    想想我需要的功能不多,只要有高亮就行,还是就简单的来写吧,继承RichTextBox;

    首先需要解决的是字体问题,我们定代码一般习惯使用等宽字体(我习惯使用宋体,10像素),rt里如果设置为宋体,在输入文字时,会自动变成arial(不等宽),因为宋体里不包含E文字库,解决这个的方法是在输入字体时,拦截输入的字符,即不让rt的keypress生效。在keypress事件里,获取字符,给selectedtext,并设置selectionfont为宋体字体,并设置e.handle=true,表示已经处理过keypress事件,rt就不会再处理这个了。

    现在需要处理核心问题之一的高亮,将文字中的关键字找出来,通过设置selectionstart和selectionlength两个属性,选中关键字部分,设置selecttioncolor属性给关键字上色,这样操作的效率很低,没办法,API里没有相关的功能(或者是我没找到)。

    如何查询将关键字,我采用的是行查询,即查询selecttionstart处的行,此行因为添加、删除、插入、替换,都会影响到整行是否关键字(或注释);查询的方法是将所有关键 放在一个集合里(比如Dictionary,我使用了一个独立的类),从行的开始处开始搜索直到行结束(0x0d,0x0a);

    上述rt上色的方法效率太低,所以,在匹配关键时,尽量将同类字符一起找出来一次性上色;首先我将字符归类,字母、数字、下线、双引号、单引号、其他符号,字母、数字、下线可以作变量,是关键字的,必须是全字母组合,在引号内的,无论是什么内容,都不用理会,直接理解为普通文本,其中双引号可以包含多组单引号;是以注释符开始的(忽略前面的空格),后面所有文字全是为注释;

    关于tab的处理,在keydown或keypress里拦截,同样,使用selectedtext=new string(" "c,4),将tab替换为4个空格,不过这样处理的话,tab就不能用来做对齐用,实际操作时,获取本行的第一个字符的索引(linefirstchar),以当前字符索引(selectionstart)减去linefirstchar,获取当前位置在本行的列索引,每tab位占4空格位,算算当前位置应该使用多少个空格来达到下一个tab位;

    复制,使用rt的copy方法就行;

    剪切,使用rt的cut方法,不过完成后还得重新处理一次高亮;

    回车,添加回车符,完成后原行和新行都要处理一次高亮(如果在关键字中间回车,关键字被切断,不处理的话还是高亮显示);

    最麻烦的是粘贴,如果是单行粘贴,处理当前行就可以了;但是多行粘贴的使用更为频繁,所以,具体的操作就是将要粘贴的text放在变量里,从变量里进行字符处理,查找词或字符组合,一部分一部分的插入到当前rt里,当然是关键字的设置高亮,注释的设置灰色,其他的设置黑色,不得不说,使用selectioncolor的效率,如果是几行,忍了,100行居然的用了1.5秒,我KAO。。。

    rt还有一个selectedrtf属性,这个属性是直接插入带格式的text,这样,研究一下rtf的存贮格式吧,将需要插入的文字以rtf的格式放在变量里,所有text处理完成之后,一次性插入rt里,连selectioncolor这一步都省了,那速度确实爽啊。500行的文字,CTRL+V立马就出来了。

    使用了rtf格式之后,在rt的new方法里,先弄一段格式文字,让rt使用此格式,比设置rt.font属性还好,在输入字符时就不需要频繁的设置selectionfont属性了。

 

    做到这里我想要的最基本的功能就完成了,不过rt有个SelectionIndent属性,这个属性可以让rt内的选中(或后输入的)文字缩进(像素单位),这不正好给我准备放一个带子显示行号吗?

    声明一个label放在rt.controls里,在label里绘制行号,rt的scroll事件可以告诉我,滚动条有滚动事件,这样在label里重新绘制就行了,提示 下,如果直接在label里绘制,闪烁是肯定的,所以我使用了bitmap作缓冲,在bitmap里绘制好了,再将bitmap直接绘制到label上(做游戏的原理),具体操作就不多哆嗦了。

    使用API的GetScrollPos绘制滚动的值(像素),以确定在什么地方绘制行号,font.height是字符行高,不过这个行高不准确,以9pt(12pixel)为例,实际行高还要加2像素才行。rt里的文字也不是从y=0开始绘制的,而是从y=2开始绘制的,多实验一下就知道是啥数值了。

    还有一个重要的,当前屏幕显示第一行的行索引,使用Api的sendmessage handle,EM_GETFIRSTVISIBLELINE,0,0可以获取,这个数字很重要,点击label时,可以将对应行全选,没这个方法,是不可能完成的。

 

    小心:SelectionIndent这个属性,如果你全选文字,删除,这个属性失败,文字光标就到了最前面,所在要在KeyUP事件里拦截delete和backspace,重新设置这个属性;

 

 

 

 

 

以上是效果图,已经达到我想要的功能:

1. 语法高亮。

2. 行号。

3. 回车随上一行缩进。

4. tab对齐

5. 点击行号选择整行

 

 

 

不尽人意的就是在输入时,输入位置行有轻微闪烁;没办法,RT的效率就这样了。

 


源代码下载: http://download.csdn.net/detail/xiaoid/5088417

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值