写过程序的人应该不会对RichTextBox感到陌生,与TextBox相比,它封装了更丰富的对象,使你的程序使用起来更加方便。但是它也有美中不足的地方。比如说没有行号,滚动条滚动进度无法控制等一系列的问题。
今天,就据我所熟悉的,向大家介绍介绍.希望达到抛砖引玉的效果,有不足的地方,还请大家积极指出来!
首先介绍如何为自己的RichTextBox增加行号。
新建一个用户控件类(UserControl),取名叫“AdaScrollRichTextBox ”继承自“System.Windows.Forms.RichTextBox ”。我们要给这个RichTextBox类加上行号,有一个比较巧妙的办法。那就是在这个类里再加上一个RichTextBox类。如下面这个方法:
private RichTextBox _LineId;
private void InitializeLineId()
{
_LineId = new RichTextBox ();
_LineId.Name = "LineId";
//_LineId.Text = "1";
_LineId.Width = 40;
_LineId.Dock = DockStyle.Left;
_LineId.Font = this.Font;
_LineId.ForeColor = Color.Green;
_LineId.ReadOnly = true;
_LineId.BackColor = Color.White;
_LineId.TabStop = false;
_LineId.BorderStyle = BorderStyle.None;
_LineId.ScrollBars = RichTextBoxScrollBars.None;
_LineId.Cursor = Cursors.Arrow;
this.SelectionIndent = 40;//由于左边行号占用了40象素,所以AdaScrollRichTextBox 需要向右边缩进40象素。
this.Controls.Add(_LineId);//注意这里,将_LineId添加进AdaScrollRichTextBox Controls。
}
在AdaScrollRichTextBox 的构造函数里调用这个方法,就可以实现行号了。
为了便于动态的绑定行号,最好是重写AdaScrollRichTextBox 的OnTextChanged方法。如下所示:
protected override void OnTextChanged(EventArgs e)
{
int liLineCount = this.Lines.Length;
for (int i = 1; I <= liLineCount; i++)
{
this._LineId.AppendText(i.ToString() + "\r\n");
}
base.OnTextChanged(e);
}
这样,当你在为AdaScrollRichTextBox 赋值的时候,便会自动为你添加行号。值得注意的是,前面我们提了,RichTextBox的ScrollBar有问题,不能控制滚动条的滚动进度。所以,程序写到目前,在效果上还是有些问题的。细心的人就会发现,当拉动滚动条的时候,行号不能跟随着滚动条的滚动一起滚动,更加不要提鼠标的滚轮了!
我们新建一个类,他继承自RichTextBox,取名“adaLineIdTxt ”。
我们知道Windows事件处理都是消息机制,你触动键盘、拖动鼠标、拖动滚动条,都会触发消息。拖动滚动条?消息?对,拖动滚动条的消息就是“Message.Msg”里的“WM_HSCROLL = 0x0114”和“WM_VSCROLL = 0x0115”。只要我们捕获到这两个消息,就可以控制拖动滚动条的滚动了。
首先,我们定义一个委托
public delegate void SendMessage(Message poMsg);
光有委托不行,我们还得定义一个事件
public event SendMessage SendMessageEvent;
以上做好之后,我们还需要重载WndProc方法。
protected override void WndProc(ref Message m)
{
if ( m.Msg == WM_VSCROLL)
{
if (SendMessageEvent != null)
{
SendMessageEvent(m);
}
}
base.WndProc(ref m);
}
//如果拖动滚动条是垂直方向(因为这里只让行号滚动,所以只有垂直方向),就触发消息。
定义一个滚动方法。
public void Scroll(Message poMsg)
{
if (this.Handle != null)
{
poMsg.HWnd = this.Handle;
WndProc(ref poMsg);
}
}
这样,我们的行号随滚动条滚动的功能就基本上实现了。下面是完整代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
namespace AdaEniac
{
public delegate void SendMessage(Message poMsg);
public partial class adaLineIdTxt : RichTextBox
{
private int WM_HSCROLL = 0x0114;
private int WM_VSCROLL = 0x0115;
public event SendMessage SendMessageEvent;
public adaLineIdTxt()
{
InitializeComponent();
}
protected override void WndProc(ref Message m)
{
if ( m.Msg == WM_VSCROLL)
{
if (SendMessageEvent != null)
{
SendMessageEvent(m);
}
}
base.WndProc(ref m);
}
public void Scroll(Message poMsg)
{
if (this.Handle != null)
{
poMsg.HWnd = this.Handle;
WndProc(ref poMsg);
}
}
}
}
需要说明的是,我前天写的“RichTextBox知识--为RichTextBox添加行号”需要做部分修改。将“_LineId”换成“adaLineIdTxt ” 类型。然后,还需要在“AdaScrollRichTextBox ”里增加一个方法
public void LineIdScroll(Message poMsg)
{
if (poMsg.Msg == (int)wm.WM_VSCROLL)
{
_LineId.Scroll(poMsg);
}
}
在你使用该控件“AdaScrollRichTextBox ”的时候,需要调用其“SendMessageEvent”事件。在该事件里,可以让行号随滚动条滚动起来。
如例private void txtView_SendMessageEvent(Message poMsg)
{
this.txtView.LineIdScroll(poMsg);
}
至此,我们为RichTextBox增加的行号已经可以随滚动条的滚动而滚动了。但是还是存在些问题,什么问题呢?
那就是滚轮滑动时,行号没滚动。
在 RichTextBox知识(二)里,我们为RichTextBox添加了随滚动条滚动的行号,但是滚轮滚动的时候,行号却没有跟随滚动!今天我们再让行号随滚轮滚动起来.具体代码见下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace AdaWinControls
{
public partial class adScrollRichTextBox : System.Windows.Forms.RichTextBox
{
public event SendMessage SendMessageEvent;
private bool _AutoLineId = true;
public bool AutoLineId
{
set
{
_AutoLineId = value;
}
get
{
return _AutoLineId;
}
}
private adLineIdTxt _LineId;
public adLineIdTxt LineId
{
get
{
return _LineId;
}
}
private bool _IsChecked = false;
public bool IsChecked
{
get
{
return _IsChecked;
}
set
{
_IsChecked = value;
}
}
public adScrollRichTextBox()
{
InitializeComponent();
InitializeLineId();
}
private void InitializeLineId()
{
_LineId = new adLineIdTxt();
_LineId.Name = "LineId";
_LineId.Text = "1";
_LineId.Width = 40;
_LineId.Dock = DockStyle.Left;
_LineId.Font = this.Font;
_LineId.ForeColor = Color.Green;
_LineId.ReadOnly = true;
_LineId.BackColor = Color.White;
_LineId.TabStop = false;
_LineId.BorderStyle = BorderStyle.None;
_LineId.ScrollBars = RichTextBoxScrollBars.None;
_LineId.Cursor = Cursors.Arrow;
this.SelectionIndent = 40;
this.Controls.Add(_LineId);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == (int)ApiVariable.WM_HSCROLL || m.Msg == (int)ApiVariable.WM_VSCROLL
|| m.Msg == (int)ApiVariable.WM_MOUSEWHEEL || m.Msg == (int)ApiVariable.EM_SCROLL
|| m.Msg == (int)ApiVariable.BM_CLICK)
{
if (SendMessageEvent != null)
{
SendMessageEvent(m);
}
}
base.WndProc(ref m);
}
public void Scroll(Message poMsg)
{
if (this.Handle != null)
{
poMsg.HWnd = this.Handle;
WndProc(ref poMsg);
}
}
public void LineIdScroll(Message poMsg)
{
if (poMsg.Msg == (int)ApiVariable.WM_VSCROLL)
{
_LineId.Scroll(poMsg);
}
}
public void NewLine(string pcLineNo, string pcLine, Color poLineColor)
{
NewLine(pcLineNo, pcLine, poLineColor, Color.White);
}
public void NewLine(string pcLineNo, string pcLine, Color poLineColor, Color poBackColor)
{
this.SelectionIndent = 40;
this.SelectionColor = poLineColor;
this.SelectionBackColor = poBackColor;
this.AppendText(pcLine + "\r\n");
this._LineId.NewLineNo(pcLineNo);
}
public void SetValue(string pcAllLine)
{
this.SelectionIndent = 40;
this.Text = pcAllLine;
this._LineId.Clear();
for (int i = 1; i <= this.Lines.Length; i++)
{
this._LineId.NewLineNo(i.ToString());
}
}
protected override void OnSizeChanged(EventArgs e)
{
_LineId.Top--;
base.OnSizeChanged(e);
}
protected override void OnTextChanged(EventArgs e)
{
this.SelectionIndent = 40;
this.SelectionHangingIndent = 40;
if (_AutoLineId)
{
this._LineId.Clear();
for (int i = 0; i < this.Lines.Length; i++)
{
this._LineId.NewLineNo(i.ToString());
}
}
base.OnTextChanged(e);
}
#region RichTextBox_ScrollVariable
private int _VPrePosition = 0;
private int _HPrePosition = 0;
// ===================================================================
// for NativeWindow and PostMessageA
private const int WM_HSCROLL = 0x114;
private const int WM_VSCROLL = 0x115;
private const int WM_MOUSEWHEEL = 0x20A;
private const int WM_COMMAND = 0x111;
// ===================================================================
// for GetScroll and PostMessageA
private const int WM_USER = 0x400;
private const int SBS_HORZ = 0;
private const int SBS_VERT = 1;
// ===================================================================
// for SubClassing
private const int SB_THUMBPOSITION = 4;
// ===================================================================
// API Function: GetScrollPos()
[DllImport("user32.dll")]
private static extern int GetScrollPos(IntPtr hWnd, int nBar);
// ===================================================================
// API Function: PostMessageA()
[DllImport("user32.dll")]
private static extern bool PostMessageA(IntPtr hwnd, int wMsg, int wParam, int lParam);
#endregion
protected override void OnVScroll(EventArgs e)
{
VerticalScrollNew(this, this._LineId);
base.OnVScroll(e);
}
private void VerticalScrollNew(RichTextBox sender, RichTextBox receiver)
{
int liPosition = GetScrollPos(sender.Handle, SBS_VERT);
if (liPosition != _VPrePosition)
{
this._VPrePosition = liPosition;
PostMessageA(receiver.Handle, WM_VSCROLL, SB_THUMBPOSITION + 0x10000 * liPosition, 0);
}
}
}
}
我们在保持前一篇截取滚动条消息的同时,引用Windows API.用它来控制行号跟随滚轮滚动.
这里需要重写"adScrollRichTextBox" 的 OnVScroll(EventArgs e)方法.有人问,为什么不连带重写OnHScroll方法呢?原因很简单,因为我们的行号只需要操作上下滚动,左右滚动就没必要了.除非你想玩BT点,让你的行好忽隐忽现.
至此,我们已经顺利的为RichTextBox添加上行号了!
我上传了资源,见地址:http://download.csdn.net/source/1078930