【问题标题】:How can I apply a MouseHover and MouseLeave to two controls to act as one control?如何将 MouseHover 和 MouseLeave 应用于两个控件以充当一个控件?
【发布时间】:2019-06-26 23:18:18
【问题描述】:

我的表单中有两个标签,它们并排放置以充当一个标签。当我将鼠标悬停在标签上时,我有一个将标签淡化为不同颜色的功能,效果很好。我正在尝试将 MouseHover 和 MouseLeave 事件应用于两个标签,这样当我将鼠标悬停在 Label1 上并移至 Label2 (反之亦然)时,该函数不会将颜色淡化回原始颜色。目前,在两个标签之间移动会激活 MouseLeave,然后在新标签中再次激活 MouseHover。

我尝试将这两个标签都添加到事件触发器中,但这没有奏效。我也尝试将两个标签都放在面板中,但这不会触发事件。

Private Sub fadeHeaderIn(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Label1.MouseHover, Label2.MouseHover
    Call fadeLabel("In")
End Sub

Private Sub fadeHeaderOut(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Label1.MouseLeave, Label2.MouseLeave
    Call fadeLabel("Out")
End Sub

如果存在更改标签部分颜色的功能,我就不需要这两个标签,所以如果有更好的方法可以完全做到这一点,我很乐意这样做。谢谢!

【问题讨论】:

  • 您可以绘制控件的任何部分。在这种情况下,您可以定义两个矩形来表示要着色的标签的两个部分。当Rectangle.Contains([MousePointer].Location) 时,绘制包含鼠标指针的矩形(对应控件的一部分)。 [MousePointer].LocationMouseMove 事件或Control.MousePositionMouseEventArgs.Location 属性引用。
  • Cursor.Position 也可以使用,以防您需要Cursor.HotSpotControl.MousePositionCursor.Position 都在屏幕坐标中提供,因此您必须将这些度量转换为客户端坐标:例如,[Control].PointToClient(Cursor.Position)
  • 感谢@Jimi 的回复;例如,您是说可以在标签的一侧涂漆吗?所以我可以设置它,如果触发了标签的 MouseHover,则文本的一半 ForeColor 发生变化,而文本的另一半 ForeColor 完全更改为不同的颜色?

标签: vb.net winforms


【解决方案1】:

我也尝试将两个标签都放在一个面板中,但是那样 不会触发事件。

应该可以。该面板将充当两个标签的边界。但是,当您从面板移动到其中包含的标签时,您会得到一个 MouseLeave。为防止误触发,只需检查鼠标是否仍在面板范围内。您可以通过使用布尔值跟踪淡入淡出状态来防止在标签之间移动时多次淡入。它看起来像这样:

Public Faded As Boolean = False

Private Sub fadeHeaderIn(sender As Object, e As EventArgs) Handles Label1.MouseHover, Label2.MouseHover
    If Not Faded Then
        Faded = True
        fadeLabel("In")
    End If
End Sub

Private Sub fadeHeaderOut(sender As Object, e As EventArgs) Handles Panel1.MouseLeave
    If Not Panel1.ClientRectangle.Contains(Panel1.PointToClient(Cursor.Position)) Then
        If Faded Then
            Faded = False
            fadeLabel("Out")
        End If
    End If
End Sub

【讨论】:

    【解决方案2】:

    这是 cmets 中描述的示例。

    控件的文本(这里是从标准标签派生的)在同一度量的两个部分中拆分。每个部分可以有不同的颜色。
    活动和非活动颜色是自定义的公共属性,可以在设计器中设置。

    每个部分都被跟踪,这意味着控件知道鼠标指针当前悬停在哪一侧。

    文本的大小是使用TextRenderer.MeasureText 方法测量的。此大小用于计算包含文本部分的矩形。
    然后使用Rectangle.Contains([Point]) 方法确定鼠标指针悬停在文本的哪个部分。 [Point] 使用MousePosition 属性计算,使用Control.PointToClient() 方法转换为客户端坐标。

    当鼠标指针从一段文本移动到另一段时(这里只有两段,可以定义更多,添加更多矩形),控件为Invalidated,导致调用@987654332 @ 控件的方法。
    如果鼠标指针没有悬停在一段文本上,则调用base.OnPaint(e)(也会引发Paint 事件),它使用默认颜色绘制默认文本。

    OnPaint 方法中,图形区域使用定义文本部分的矩形进行裁剪。随后调用TextRenderer.DrawText,设置TextFormatFlags.PreserveGraphicsClipping 标志,剪切定义区域中的文本,因此只绘制适合剪切区域的文本部分。
    这里使用Graphics.ExcludeClip() 方法来定义这些剪辑区域。

    TextFormatFlags.ExternalLeadingTextFormatFlags.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
    

    【讨论】:

      猜你喜欢
      • 2012-09-15
      • 1970-01-01
      • 1970-01-01
      • 2017-06-11
      • 2011-08-13
      • 1970-01-01
      • 2012-09-11
      • 2012-08-20
      • 1970-01-01
      相关资源
      最近更新 更多