这是 cmets 中描述的示例。
控件的文本(这里是从标准标签派生的)在同一度量的两个部分中拆分。每个部分可以有不同的颜色。
活动和非活动颜色是自定义的公共属性,可以在设计器中设置。
每个部分都被跟踪,这意味着控件知道鼠标指针当前悬停在哪一侧。
文本的大小是使用TextRenderer.MeasureText 方法测量的。此大小用于计算包含文本部分的矩形。
然后使用Rectangle.Contains([Point]) 方法确定鼠标指针悬停在文本的哪个部分。 [Point] 使用MousePosition 属性计算,使用Control.PointToClient() 方法转换为客户端坐标。
当鼠标指针从一段文本移动到另一段时(这里只有两段,可以定义更多,添加更多矩形),控件为Invalidated,导致调用@987654332 @ 控件的方法。
如果鼠标指针没有悬停在一段文本上,则调用base.OnPaint(e)(也会引发Paint 事件),它使用默认颜色绘制默认文本。
在 OnPaint 方法中,图形区域使用定义文本部分的矩形进行裁剪。随后调用TextRenderer.DrawText,设置TextFormatFlags.PreserveGraphicsClipping 标志,剪切定义区域中的文本,因此只绘制适合剪切区域的文本部分。
这里使用Graphics.ExcludeClip() 方法来定义这些剪辑区域。
TextFormatFlags.ExternalLeading 和 TextFormatFlags.TextBoxControl 也用于复制默认文本呈现,因此自定义文本呈现在相同的相对位置。
这是它的行为方式:
自定义控件类来测试功能:
Imports System.ComponentModel
Imports System.Drawing
Imports System.Windows.Forms
<DesignerCategory("Code")>
Public Class LabelSplitText
Inherits Label
Private m_Text As String = String.Empty
Private m_Sections As RectangleF() = Nothing
Private m_PaintText As Boolean = False
ReadOnly flags As TextFormatFlags = TextFormatFlags.ExternalLeading Or
TextFormatFlags.PreserveGraphicsClipping Or
TextFormatFlags.TextBoxControl
Public Sub New()
InitializeComponent()
End Sub
Private Sub InitializeComponent()
ResizeRedraw = True
End Sub
Public ReadOnly Property ActiveRectangle As RectangleF
Public ReadOnly Property ActiveSide As String = String.Empty
Public Property ActiveColor As Color = Color.White
Public Property InactiveColor As Color = Color.DimGray
Protected Overrides Sub OnLayout(e As LayoutEventArgs)
MyBase.OnLayout(e)
Me.AutoSize = False
m_Text = Me.Text
End Sub
Protected Overrides Sub OnMouseEnter(e As EventArgs)
m_Text = Me.Text
Text = String.Empty
m_PaintText = True
MyBase.OnMouseEnter(e)
Invalidate()
End Sub
Protected Overrides Sub OnMouseLeave(e As EventArgs)
m_PaintText = False
Me.Text = m_Text
MyBase.OnMouseLeave(e)
End Sub
Protected Overrides Sub OnMouseMove(e As MouseEventArgs)
MyBase.OnMouseMove(e)
Invalidate()
If m_Sections Is Nothing Then Return
Me._ActiveRectangle = If(m_Sections(0).Contains(e.Location), m_Sections(0), m_Sections(1))
End Sub
Protected Overrides Sub OnMouseClick(e As MouseEventArgs)
Me._ActiveSide = If(m_Sections(0).Contains(e.Location), "left", "right")
MyBase.OnMouseClick(e)
End Sub
Protected Overrides Sub OnPaint(e As PaintEventArgs)
If Not m_PaintText Then
MyBase.OnPaint(e)
Return
End If
Dim textSize As SizeF = TextRenderer.MeasureText(e.Graphics, m_Text, Me.Font, Me.ClientSize, flags)
m_Sections = GetTextAreaSections(textSize)
e.Graphics.ExcludeClip(Rectangle.Round(m_Sections(1)))
TextRenderer.DrawText(e.Graphics, m_Text, Me.Font, Point.Empty, GetSectionColor(0), flags)
e.Graphics.ResetClip()
e.Graphics.ExcludeClip(Rectangle.Round(m_Sections(0)))
TextRenderer.DrawText(e.Graphics, m_Text, Me.Font, Point.Empty, GetSectionColor(1), flags)
End Sub
Private Function GetSectionColor(section As Integer) As Color
Return If(m_Sections(section).Contains(PointToClient(MousePosition)),
Me.ActiveColor, Me.InactiveColor)
End Function
Private Function GetTextAreaSections(textSize As SizeF) As RectangleF()
If textSize.Width > Me.ClientSize.Width Then textSize.Width = Me.ClientSize.Width
Dim rectLeft = New RectangleF(PointF.Empty,
New SizeF(textSize.Width / 2.0F, Me.ClientSize.Height))
Dim rectRight = New RectangleF(New PointF(textSize.Width / 2.0F, 0),
New SizeF(textSize.Width / 2.0F, Me.ClientSize.Height))
Return {rectLeft, rectRight}
End Function
End Class