用于富文本控件的通用标尺控件






4.88/5 (16投票s)
一个 UserControl,允许富文本应用程序拥有一个带有边距、缩进和制表符支持的标尺
上图:TextRuler 控件放置在宿主 RichTextBox 和 Label 控件的上方。
最后更新:2024年9月9日
引言
此 TextRuler
是一个 UserControl
,可以与任何富文本框控件集成,允许用户为富文本控件创建、删除和移动边距、缩进和制表符。
- 它允许程序员设置标尺的有效宽度(不要与控件的宽度混淆!),以及用户可以通过点击/拖动来操作哪些类型的标记(边距、缩进、制表符)。
- 它具有属性和事件,可以同步富文本控件的边距/缩进/制表符值和此控件的值。
- 标尺可以配置为以英寸(每1/8英寸刻度)或厘米(每5毫米(1/2厘米)刻度)进行测量。
- 它支持工具提示,包括默认的“特殊”工具提示文本,以便在用户将鼠标悬停在标记上时显示。
- 它支持处理是否应滚动显示,以确保其标记与宿主富文本控件的边距/缩进/制表符值对齐。
- 它可以通过
ZoomFactor
进行缩放,以同步富文本控件中文本的放大/缩小。 - 这 5 个事件现在由受保护的“On”方法引发,以便于为任何派生类进行重写(2021年12月28日)。
此控件源自 Aleksei Karimov 的 Advanced Text Editor with Ruler 中的“TextRuler
” UserControl
,标尺控件的代码已转换为 VB.NET,并进行了许多修改和增强。新版本旨在成为一个 通用
“独立”控件,然后可以添加到/集成到 任何
富文本基础的 UserControl
或项目中。
Using the Code
TextRuler 的属性
属性如下
MarkerUnderMouse / TabUnderMouse -- MarkerUnderMouse
返回一个MarkerType
枚举值,指示鼠标当前悬停在何种类型的标记上。如果是一个制表符,则TabUnderMouse
返回鼠标下方制表符的像素位置。TabsEnabled
-- 获取或设置标尺是否显示或允许用户设置制表符停止位。MaximumTabs
-- 获取或设置允许的最大制表符数量。注意: 设置时,如果值小于当前制表符数量,则此属性不会被更改。(9/9/2024 之前属性存在但未记录。)TabPositions
/TabPositionsInUnits
-- 获取或设置任何Integer
/Single
数组,其中包含像素为单位的制表符位置(TabPositions
)或当前Units-
属性类型(TabPositionsInUnits
)。与TabPositions
相当的RichTextBox
属性是SelectionTabs
。PixelsPerCentimeter
/PixelsPerInch
-- 只读--返回每厘米/每英寸的像素数,用于进行转换;这些值是Single
类型,以便于对大值进行精确转换。Units
-- 获取或设置一个UnitType
枚举值,表示标尺当前使用的单位类型;可以是Inches
(默认)或Centimeters
。ToolTipText
-- 获取或设置控件的工具提示String
。如果UsingSmartTooltips
为True
,则当鼠标悬停在边距/缩进/制表符标记上时,将显示默认的描述性名称。UsingSmartToolTips
-- 获取或设置工具提示文本是否应在鼠标悬停在标记上时描述标记类型。如果您想自己指定要使用的工具提示类型,请将此值设置为False
,并在事件代码中使用MarkerUnderMouse
属性来确定用户悬停在何处。BorderColor
/BaseColor
-- 获取或设置标尺边框的颜色或边框内的背景颜色。RulerWidth
/PrintableWidth
-- 获取或设置标尺应处理的水平空间(像素)——包含/不包含任何边距。与PrintableWidth
相当的RichTextBox
属性是富文本控件的RightMargin
属性(当该属性非零时)。RulerWidth
是PrintableWidth
加上任何左边距和右边距空间。(注意:这些不是控件的Width
类型属性。)ScrollingOffset
-- 获取或设置从标尺起始位置开始绘制并跟踪标记的像素偏移量。这使得在文本水平滚动时,标尺标记可以与富文本对齐。NoMargins
-- 获取或设置标尺是否应包含左侧和/或右侧不属于标记设置或拖动范围的空间。将此值设置为True
会将LeftMargin
和RightMargin
属性设置为零。(对于基本的RichTextBox
控件,它不显示超出范围的空间,请将此值设置为True
。)LeftMargin
/RightMargin
-- 获取或设置标尺左侧/右侧应为标记保留的无效像素区域。要设置这些属性,NoMargins
必须为False
。(注意:这里的RightMargin
属性从标尺右边缘向左测量,而RichTextBox
的RightMargin
属性从文本行的左侧边缘向右测量。)FirstLineIndent
/LeftIndent
-- 获取或设置段落的第一行应从左边距开始的像素偏移量。这些属性的区别在于设置时:设置FirstLineIndent
只改变段落文本第一行的位置,而将后续行的位置保留在当前位置(并相应调整HangingIndent
);而设置LeftIndent
会将所有行在同等距离上向左或向右移动(HangingIndent
保持不变)。与LeftIndent
相当的RichTextBox
属性是SelectionIndent
。HangingIndent
-- 获取或设置段落后续行缩进相对于第一行缩进的像素偏移量。负值使段落的后续行比第一行缩进更少,正值使它们比第一行缩进更多,零则使它们对齐。与HangingIndent
相当的RichTextBox
属性是SelectionHangingIndent
。RightIndent
-- 获取或设置段落行在右边距之前应停止的像素偏移量。与RightIndent
相当的RichTextBox
属性是SelectionRightIndent
。- ZoomFactor -- 获取 或设置标尺显示的放大或缩小比例;对应于同名的
RichTextBox
属性。与RichTextBox
一样,ZoomFactor
仅影响边距、缩进和制表符的显示大小——关联属性的像素/单位值将是ZoomFactor
为 1 时的值。也就是说,设置时它们的位置会根据ZoomFactor
进行缩放显示,读取时会从显示中反向缩放。RulerWidth
/PrintableWidth
属性,就像RichTextBox
的RightMargin
属性一样,不受缩放影响,因此放大/缩小显示会减小/增大标尺的逻辑范围,就像在RichTextBox
中放大一样会影响一行文本能容纳的物理文本量。
TextRuler 的方法
方法如下
- value =
PixelsToUnits(pixels)
-- 将给定的像素数转换为英寸或厘米的等效值,具体取决于Units
属性的值。 - value =
UnitsToPixels(units)
-- 将给定的英寸或厘米数(取决于Units
属性的值)转换为等效的像素值。
TextRuler 的事件
事件如下
IndentsChanged/ MarginsChanged
-- 当用户更改缩进或边距值时触发。输入
MarginOrIdentEventArgs.MarkerType
-- 移动的缩进或边距的类型MarkerType
值。
TabAdded / TabRemoved / TabChanged
-- 用户分别添加、删除或移动制表符位置时触发。输入
TabEventArgs.OldPosition
-- 被移动或删除的制表符的原始像素位置。TabEventArgs.NewPosition
-- 被添加或移动的制表符的新像素位置。
注意
这些事件仅在用户更改边距/缩进/制表符时触发,而不在程序员通过代码更改这些值时触发。此外,它们在更改已经发生后触发,因此不直接支持取消更改。
示例代码片段
下面提供了一些代码示例
Imports TextRuler
' getting info from rich-text box
Private Sub RTBToRuler()
TextRuler1.NoMargins = True : TextRuler1.PrintableWidth = RichTextBox1.RightMargin
TextRuler1.Units = MarkerType.Inches
TextRuler1.ScrollingOffset = TextRuloer1.UnitsToPixels(1/4) 'scroll past first quarter-inch
TextRuler1.FirstLineIndent = RichTextBox1.SelectionIndent
TextRuler1.HangingIndent = RichTextBox1.SelectionHangingIndent
TextRuler1.RightIndent = RichTextBox1.SelectionRightIndent
TextRuler1.TabPositions = RichTextBox1.SelectionTabs
TextRuler1.ZoomFactor = RichTextBox1.ZoomFactor
End Sub
' setting info into rich-text box
Private Sub RulerToRTB()
RichTextBox1.SelectionIndent = TextRuler1.FirstLineIndent
RichTextBox1.SelectionHangingIndent = TextRuler1.HangingIndent
RichTextBox1.SelectionRightIndent = TextRuler1.RightIndent
RichTextBox1.SelectionTabs = TextRuler1.TabPositions
End Sub
' event
Public Sub IndentsChanged(sender As Object, e As MarginOrIndentEventArgs) _
Handles TextRuler1.IndentsChanged
RulerToRTB()
' display what was changed and current right-indent value in current units
Dim s As String = e.MarkerType.ToString.Replace("_", " ") _
& " changed. Right Indent = " _
& TextRuler1.PixelsToUnits(TextRuler1.RightIndent).ToString _
If TextRuler1.Units = UnitType.Inches Then
s &= " inches"
Else
s &= " centimeters"
End If
Label1.Text = s
End Sub
演示程序
示例应用程序显示了一个富文本框,上方有一个标尺,下方有一个标签(参见文章顶部);后者以英寸或厘米显示当前的缩进和制表符位置。(右键单击标尺可在单位之间选择。)窗体的代码文件包含一个 Module
,其中定义了一个扩展方法 GetScrollPosition
,用于在文本框中的文本滚动时获取水平滚动位置,以便标尺标记相应地进行水平同步。(它使用非托管的 Win32 API SendMessage
。)最后,我应该指出,程序会考虑富文本控件是否在任何文本左侧显示 8 像素的“选择边距”,以进行对齐。
兴趣点
- 该控件不会允许用户或程序员以使缩进或制表符超出“可打印宽度”区域(即,超出边距空间)或使最右侧的左缩进与右缩进挤压在一起的方式来设置边距、缩进和制表符。此外,它也不会允许创建 2 个或更多重叠的制表符位置,或将现有制表符移出顺序(即,将一个制表符移到另一个制表符之上)。这些规则部分是为了防止控件在跟踪鼠标时混淆标记,部分是为了简化编码。要实现“边距释放”(即制表符或缩进可以出现在边距中),请仔细研究源代码。所有信息都以像素为单位内部存储,缩进表示为与左右边缘(包括边距)的绝对距离,制表符表示为相对于滚动偏移量和缩放因子的距离。(注意:如果用户/程序员尝试将值设置为不可接受的内容,则不会抛出异常;相反,尝试的更改将被简单地忽略。)
- 如果您希望允许程序代码提前“取消”用户更改,我建议创建 5 个额外的事件,这些事件在更改之前触发,并使用具有与
MarginOrIndentEventArgs
和TabEventArgs
相同属性的参数类,但这些类继承自CancelEventArgs
。 - 我已更新了我自己的文本编辑器
UserControl
,EXTENDED Version of Extended Rich Text Box (RichTextBoxEx),将此标尺作为其组成控件。