.Net TrackMouseEvent 不适用于子菜单项

发布于 2024-12-03 07:18:31 字数 2485 浏览 0 评论 0原文

我正在向我创建的自定义 ContextMenuStrip 控件添加一些功能。

我需要做的第一件事是增加鼠标悬停在子菜单上下文项上的时间。以下代码非常适合主上下文项,但不会触发子菜单项的鼠标悬停事件。

我相信问题是我需要将 tme.hWnd 句柄设置为子菜单。如果是这种情况,如何在子菜单打开时获取其句柄?

谢谢!

    Friend Const WM_MOUSEMOVE As Integer = &H200
    Friend Const WM_MOUSELEAVE As Integer = &H2A3
    Friend Const TME_LEAVE As Integer = &H2

    Private _mouseOver As Boolean = False
    Private _mouseOverHandel As IntPtr = Me.Handle

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)

        Select Case m.Msg
            Case WM_MOUSEMOVE
                If Not _mouseOver Then

                    Dim tme As New TRACKMOUSEEVENTR()
                    tme.hWnd = _mouseOverHandel
                    tme.cbSize = Marshal.SizeOf(GetType(TRACKMOUSEEVENTR))
                    tme.dwFlags = TMEFlags.TME_HOVER
                    tme.dwHoverTime = 1000 * 3
                    TrackMouseEvent(tme)

                    _mouseOver = True
                End If

                MyBase.WndProc(m)
                Exit Select

            Case WM_MOUSELEAVE
                _mouseOver = False
                MyBase.WndProc(m)
                Exit Select

            Case Else
                MyBase.WndProc(m)
        End Select

    End Sub


    <DllImport("user32.dll")> _
    Private Shared Function TrackMouseEvent(ByRef lpEventTrack As TRACKMOUSEEVENTR) As Integer
    End Function

    <StructLayout(LayoutKind.Sequential)> _
    Public Structure TRACKMOUSEEVENTR
        Public cbSize As Int32
        ' using Int32 instead of UInt32 is safe here, and this avoids casting the result  of Marshal.SizeOf()
        <MarshalAs(UnmanagedType.U4)> _
        Public dwFlags As TMEFlags
        Public hWnd As IntPtr
        Public dwHoverTime As UInt32

        Public Sub New(dwFlags As Int32, hWnd As IntPtr, dwHoverTime As UInt32)
            Me.cbSize = Marshal.SizeOf(GetType(TRACKMOUSEEVENTR))
            Me.dwFlags = dwFlags
            Me.hWnd = hWnd
            Me.dwHoverTime = dwHoverTime
        End Sub
    End Structure

    ''' <summary>
    ''' The services requested. This member can be a combination of the following values. 
    ''' </summary>
    <Flags()> _
    Public Enum TMEFlags As UInteger
        TME_CANCEL = &H80000000UI
        TME_HOVER = &H1
        TME_LEAVE = &H2
        TME_NONCLIENT = &H10
        TME_QUERY = &H40000000
    End Enum

I am adding some functionality to a custom ContextMenuStrip control that I have created.

One of the first things that I need to do is increase the mouse hover time on the submenu context items. The following code works perfectly for the main context items, but will not fire my mouse hover event for submenu items.

I believe the problem is that I need to set the tme.hWnd handle to the submenu. If that is the case, how do I get the handle of the submenu as it is opening?

Thanks!

    Friend Const WM_MOUSEMOVE As Integer = &H200
    Friend Const WM_MOUSELEAVE As Integer = &H2A3
    Friend Const TME_LEAVE As Integer = &H2

    Private _mouseOver As Boolean = False
    Private _mouseOverHandel As IntPtr = Me.Handle

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)

        Select Case m.Msg
            Case WM_MOUSEMOVE
                If Not _mouseOver Then

                    Dim tme As New TRACKMOUSEEVENTR()
                    tme.hWnd = _mouseOverHandel
                    tme.cbSize = Marshal.SizeOf(GetType(TRACKMOUSEEVENTR))
                    tme.dwFlags = TMEFlags.TME_HOVER
                    tme.dwHoverTime = 1000 * 3
                    TrackMouseEvent(tme)

                    _mouseOver = True
                End If

                MyBase.WndProc(m)
                Exit Select

            Case WM_MOUSELEAVE
                _mouseOver = False
                MyBase.WndProc(m)
                Exit Select

            Case Else
                MyBase.WndProc(m)
        End Select

    End Sub


    <DllImport("user32.dll")> _
    Private Shared Function TrackMouseEvent(ByRef lpEventTrack As TRACKMOUSEEVENTR) As Integer
    End Function

    <StructLayout(LayoutKind.Sequential)> _
    Public Structure TRACKMOUSEEVENTR
        Public cbSize As Int32
        ' using Int32 instead of UInt32 is safe here, and this avoids casting the result  of Marshal.SizeOf()
        <MarshalAs(UnmanagedType.U4)> _
        Public dwFlags As TMEFlags
        Public hWnd As IntPtr
        Public dwHoverTime As UInt32

        Public Sub New(dwFlags As Int32, hWnd As IntPtr, dwHoverTime As UInt32)
            Me.cbSize = Marshal.SizeOf(GetType(TRACKMOUSEEVENTR))
            Me.dwFlags = dwFlags
            Me.hWnd = hWnd
            Me.dwHoverTime = dwHoverTime
        End Sub
    End Structure

    ''' <summary>
    ''' The services requested. This member can be a combination of the following values. 
    ''' </summary>
    <Flags()> _
    Public Enum TMEFlags As UInteger
        TME_CANCEL = &H80000000UI
        TME_HOVER = &H1
        TME_LEAVE = &H2
        TME_NONCLIENT = &H10
        TME_QUERY = &H40000000
    End Enum

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一页 2024-12-10 07:18:31

我不得不采取另一种方式来解决这个问题。我会把它留在这里给任何需要它的人。

我为动态子菜单项创建了 MouseMove 和 MouseLeave 处理程序。

在鼠标内部移动

If Not _mouseSubOver Then

    _tsmi = sender

    _itemDelayTimer = New Timer()
    _itemDelayTimer.Interval = Math.Max(1, 1500)
    AddHandler _itemDelayTimer.Tick, AddressOf OnDelayTimerExpire
    _itemDelayTimer.Start()

    _mouseSubOver = True

End If

在鼠标内部离开

If _itemDelayTimer IsNot Nothing Then
    _itemDelayTimer.Stop()
    _itemDelayTimer.Dispose()
    _itemDelayTimer = Nothing
End If

_mouseSubOver = False

内部 OnDelayTimerExpire

 Private Sub OnDelayTimerExpire(sender As Object, e As EventArgs)
        If _itemDelayTimer IsNot Nothing Then

            _itemDelayTimer.Stop()
            _itemDelayTimer.Dispose()
            _itemDelayTimer = Nothing

        End If

        'Do your sub menu stuff here
 End Sub

I had to go another way to solve this. I'll leave this here for anyone that needs it.

I created a MouseMove and MouseLeave handler for my dynamic submenu items.

Inside the MouseMove

If Not _mouseSubOver Then

    _tsmi = sender

    _itemDelayTimer = New Timer()
    _itemDelayTimer.Interval = Math.Max(1, 1500)
    AddHandler _itemDelayTimer.Tick, AddressOf OnDelayTimerExpire
    _itemDelayTimer.Start()

    _mouseSubOver = True

End If

Inside MouseLeave

If _itemDelayTimer IsNot Nothing Then
    _itemDelayTimer.Stop()
    _itemDelayTimer.Dispose()
    _itemDelayTimer = Nothing
End If

_mouseSubOver = False

Inside OnDelayTimerExpire

 Private Sub OnDelayTimerExpire(sender As Object, e As EventArgs)
        If _itemDelayTimer IsNot Nothing Then

            _itemDelayTimer.Stop()
            _itemDelayTimer.Dispose()
            _itemDelayTimer = Nothing

        End If

        'Do your sub menu stuff here
 End Sub
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文