Как я могу применить MouseHover и MouseLeave к двум элементам управления, чтобы действовать как один элемент управления? - PullRequest
1 голос
/ 27 июня 2019

У меня есть две метки в моей форме, которые расположены рядом, чтобы действовать как одна метка.Когда я наводю курсор на метки, у меня есть функция, которая делает метки разными цветами, и это хорошо работает.Я пытаюсь применить события MouseHover и MouseLeave к обеим меткам, чтобы при наведении курсора на Label1 и переходе к Label2 (и наоборот) функция не затемняла цвет обратно к исходному цвету.В настоящее время перемещение между двумя метками активирует MouseLeave и снова MouseHover в новой метке.

Я попытался добавить обе метки в триггер события, но это не сработало.Я также попытался поместить обе метки в Panel, но это не вызывает событие.

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

Если бы существовала функциональность для изменения цвета части метки, мне бы не понадобилосьдве метки, так что, если есть лучший способ сделать это в целом, я счастлив сделать это.Спасибо!

Ответы [ 2 ]

0 голосов
/ 27 июня 2019

Вот пример того, что было описано в комментариях.

Текст элемента управления (здесь, полученный из стандартной метки) разделен на две части одной и той же меры. Каждый раздел может иметь свой цвет.
Активные и неактивные цвета являются настраиваемыми общедоступными свойствами, их можно установить в конструкторе

Каждый раздел отслеживается , что означает, что элемент управления знает о том, с какой стороны в данный момент находится указатель мыши.

Размер текста измеряется с помощью метода TextRenderer.MeasureText . Этот размер используется для вычисления прямоугольников, которые включают фрагменты текста.
Затем метод Rectangle.Contains ([Point]) используется для определения того, какой раздел текста при наведении курсора мыши. [Point] рассчитывается с использованием свойства MousePosition , переведенного в клиентские координаты с использованием метода Control.PointToClient () .

Когда указатель мыши перемещается из одного раздела текста в другой (здесь можно определить только два раздела, добавив больше прямоугольников), элемент управления будет недействительным , вызывая вызов OnPaint метод контроля.
Если указатель мыши не наведен на часть текста, вызывается base.OnPaint(e) (что также вызывает событие Paint), при котором текст по умолчанию отображается цветом по умолчанию.

В методе OnPaint область Графика обрезается с помощью прямоугольников, определяющих текстовые разделы. Последующий вызов TextRenderer.DrawText , установка флага TextFormatFlags.PreserveGraphicsClipping , обрезает текст в определенной области, поэтому закрашивается только часть текста, которая умещается в области отсечения.
Метод Graphics.ExcludeClip () используется здесь для определения этих областей отсечения.

TextFormatFlags.ExternalLeading и TextFormatFlags.TextBoxControl также используются для репликации текстового рендеринга по умолчанию, поэтому пользовательский текст отображается в той же относительной позиции.

Вот как это ведет себя:

Custom Control Label Split Text

Пользовательский класс управления для проверки функциональности:

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
0 голосов
/ 27 июня 2019

Я также пытался разместить обе метки на панели, но это не вызывает событие.

Это должно сработать.Панель будет действовать как границы для обеих меток.Однако вы получите 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...