在 .NET 2.0 中 RichTextBox 的行号






4.07/5 (16投票s)
使用 PictureBox 控件绘画的 RichTextBox 控件的行号。
引言
本文演示了如何向 RichTextBox
控件添加行号。这是通过在富文本框控件的左侧添加一个 PictureBox
控件来完成的。当 Form
或 RichTextBox
控件上发生适当的事件时,我们调用一个方法,该方法在 PictureBox
控件上绘制行号。这种方法比我见过的其他方法更准确、更有效,在其他方法中,使用另一个文本框控件来打印行号。PictureBox
将只打印当前在 RichTextBox
控件中可见的行号。在构建此代码示例的过程中,我最初是基于文章中提供的代码示例:https://codeproject.org.cn/cs/miscctrl/numberedtextbox.asp,并通过以下方式对其进行了增强
- 用
PictureBox
替换用于编号的Label
控件。 - 我修复了该实现中由于
RichTextBox
使用平滑滚动(使用滚动条滚动以像素为单位而不是以行为单位滚动)而导致的滚动问题。因此,有时第一行可能会显示一半,在这种情况下,行号应该解决这个问题。
以下是打印行号的代码。请注意,我们有一个名为 MyRichTextBox
的 RichTextBox
控件和一个名为 MyPictureBox
的 PictureBox
控件。该方法获取一个参数,即 PictureBox
控件的 Graphics
。这是 DrawRichTextBoxLineNumbers
方法
Private Sub DrawRichTextBoxLineNumbers(ByRef g As Graphics)
'Calculate font heigth as the difference in Y coordinate
'between line 2 and line 1
'Note that the RichTextBox text must have at least two lines.
' So the initial Text property of the RichTextBox
' should not be an empty string. It could be something
' like vbcrlf & vbcrlf & vbcrlf
With MyRichTextBox
Dim font_height As Single
font_height = .GetPositionFromCharIndex(.GetFirstCharIndexFromLine(2)).Y _
- .GetPositionFromCharIndex(.GetFirstCharIndexFromLine(1)).Y
If font_height = 0 Then Exit Sub
'Get the first line index and location
Dim first_index As Integer
Dim first_line As Integer
Dim first_line_y As Integer
first_index = .GetCharIndexFromPosition(New _
Point(0, g.VisibleClipBounds.Y + font_height / 3))
first_line = .GetLineFromCharIndex(first_index)
first_line_y = .GetPositionFromCharIndex(first_index).Y
'Print on the PictureBox the visible line numbers of the RichTextBox
g.Clear(Control.DefaultBackColor)
Dim i As Integer = first_line
Dim y As Single
Do While y < g.VisibleClipBounds.Y + g.VisibleClipBounds.Height
y = first_line_y + 2 + font_height * (i - first_line - 1)
g.DrawString((i).ToString, .Font, Brushes.DarkBlue, MyPictureBox.Width _
- g.MeasureString((i).ToString, .Font).Width, y)
i += 1
Loop
'Debug.WriteLine("Finished: " & firstLine + 1 & " " & i - 1)
End With
End Sub
此方法应从以下位置调用
- 在
RichTextBox
的Resize
事件上:DrawRichTextBoxLineNumbers(MyPictureBox.CreateGraphics)
。 - 当
VScroll
事件发生在RichTextBox
上时:(MyRichTextBox.VScroll).DrawRichTextBoxLineNumbers(MyPictureBox.CreateGraphics)
。 - 当
Paint
事件发生时:(MyPictureBox.Paint).DrawRichTextBoxLineNumbers(e.Graphics)
。请注意,在这种方法中,我们发送e.Graphics
而不是MyPictureBox.CreateGraphics
,因为我们只想重绘PictureBox
控件内的所需区域。
这些是我们调用行号方法的位置
Private Sub r_Resize(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles MyRichTextBox.Resize
MyPictureBox.Invalidate()
End Sub
Private Sub r_VScroll(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles MyRichTextBox.VScroll
MyPictureBox.Invalidate()
End Sub
Private Sub p_Paint(ByVal sender As Object, _
ByVal e As System.Windows.Forms.PaintEventArgs) _
Handles MyPictureBox.Paint
DrawRichTextBoxLineNumbers(e.Graphics)
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles MyBase.Load
MyRichTextBox.Text = vbCrLf & vbCrLf & vbCrLf
End Sub
其他一般说明
- 上面的代码假设
RichTextBox
控件的字体名称和大小对于整个文本是相同的。 RichTextBox
控件的WordWrap
属性应设置为False
。- 我将此代码放在
Form_Load
方法中,以确保文本框始终至少有两行 - 我建议将
PictureBox
停靠在左侧,然后根据g.MeasureString("000", MyRichTextBox.Font).Width
计算PictureBox
的宽度。当RichTextBox
的字体更改时,应重新计算PictureBox
的宽度,并应重新绘制PictureBox
。 PictureBox
控件可以替换为Panel
或任何其他公开CreateGraphics()
方法的控件。- 该控件是为
WordWrap = False
的RichTextBox
控件设计的。
MyRichTextBox.Text = vbCrLf & vbCrLf & vbCrLf