博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
感觉上用C#来写这种扩充组件确实比较麻烦。一个调用系统级的API需要用DllImport来封装,比较麻烦。特别是用SendMessage时,一大堆的message id等常量需要查资料。二个就是.net组件封装得太厉害。封装厉害倒不是件什么坏事,但是总得考虑用户重写某些接口的可能,应该将接口多用virtual修饰允许重写吧?
  好,牢骚到此结束,现在言归正传。从Richtextbox继承的语法高亮控件已经很多。原理基本一样。有些控件实现了显示行号的功能(本控件也是),可以算是一个亮点吧。下面从几个方面来讲述。

1. 语法高亮
  当用户插入一个字符的时候,有些控件的实现会将整个Text扫描一遍,对各个关键字进行处理。这个包含了很多重复的工作,效率有点低。既然内容是控件自身管理,那么就可以断定:除了插入点临近的地方高亮模式被破坏以外,其它的地方都是不需要改变的。因此,只需要对插入点向左、向右(向前和向后太容易混淆弄糊涂)检查相邻的第一个Word是不是关键字就可以了。
Code: ProcessHighlight

将关键字高亮也挺简单,就是先选中一段文字,然后设置SelectionColor=Color.Blue。
Code:DoHighlightWord

  但是这也带来了新的问题,就是必须处理粘贴的文本。本控件在这个版本就没有加入对它的实现。打算在以后的版本再做吧。

2. 显示行号
  这个问题要完美地解决还真不简单。我在写代码的时候,想了很多的办法,结果还是没有很好地解决这个问题。
  我的做法是,在主TextBox中嵌入一个独立的靠左的TextBox显示行号。为了使TextBox不遮住内容,在插入字符时,设置TextBox的SelectionIndent为一个固定值。当然普通的Textbox是不能用的,需要重写。重写的主要目的是:(1)去掉textBox的光标,让它不像一个可输入的控件。(2)在右边画一条竖的虚线。(3)加入显示行号的逻辑。
  去掉textBox的光标的做法是,textBox获得Focus的时候,立即让它失去Focus。代码如下:
void RowNumTextBox_GotFocus(object sender, EventArgs e)
{
    Native.SendMessage(
this.Handle, WinMsgs.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
}
  
  现在的情况是,TextBox显示内容,另一个TextBox显示行号。但在滚动内容时,又想让行号跟着滚动。这就有了同步的问题。要说.net封装得太厉害,想要实现某些功能却又不能。比如监听TextBox的滚动条的滚动位置。这个事件没有办法监听,只能从引起滚动条变化的因素入手。在之前,先说明,让TextBox内容自动滚动,可以对某个TextBox发送EM_LINESCROLL事件。看代码:
Code:ScrollRowNumberTextBox

然后重写WndProc方法,当以下事件发生时,调用ScrollRowNumberTextBox滚动行号方法。
WM_VSCROLL
EM_SCROLL
EM_LINESCROLL
WM_MOUSEWHEEL
消息的相关意思可以查阅MSDN。此外,当内容有改变时,也需要调用ScrollRowNumberTextBox并更新行号。
Code: WndProc


3. 代码中有许多直接用SendM种essage来操作控件。这原生的Windows API真是异常地生猛。如果要开发出一个可用的代码编辑器来,还不如用WIN32编程来得直接。最后看看截图。


下载示例:/Files/qkhh/Editor.zip
下载源码:/Files/qkhh/Editor-Soruce.zip
源码请用VS2008(SP1)打开。
posted on 2009-09-05 15:00  黑米  阅读(620)  评论(1编辑  收藏  举报