Is there a way to set the period of time that the mouse must be over a control in order to trigger its MouseHover event?
Asked Answered
T

1

1

I need a way to set the MouseHoverTime Property, or some other way of making it so that the mouse needs to be over a control for a given amount of time before an event kicks in.

I have a set of controls that need to execute code when the mouse passes onto them, which can be done with either MouseEnter or MouseHover. However, when the mouse passes quickly over many of these controls, the code event for each control gets run in full. This makes the running of the program painfully and impractically slow. If I could set a certain time threshold for the mouse to stay over the control, then the event would only be called when the mouse stays over the control, and not when it briefly passes over it.

Private Sub Tile_MouseHover(Sender As Object, e As EventArgs)

CODE
CODE
CODE

End Sub

The code does give the intended results. It just gives them at a snails pace, because every time the cursor so much as brushes a control, all of the code within it gets executed.

The goal results would be as follows:

When the cursor hovers over a control, it must remain there for 1-2 seconds before calling the event. If the cursor leaves before this, the event doesn't get called at all.

Timms answered 7/2, 2019 at 19:49 Comment(8)
the mousehovertime is a system-wide metric. consider a solution where you use a precision timer in combination with the mouseenter and mouseleave events to create the treshold. I don't see how this would improve the "painfully slow" issue. its just postponed. there should not be any long-running UI tasks. what are you trying to achieve, on a high user interaction design level?Regulator
@dlatikay Thanks for the answer. The user should be able to highlight a given tile on the screen by hovering the mouse over it, and lock that highlight by clicking on the tile. Certain properties of the tile will be displayed elsewhere onscreen. I have achieved this already using MouseHover and MouseClick events but the speed issue comes into play when the user tries to hover over a distant tile. This is because every tile in between the start and destination gets "Hovered" and has its event called.Timms
@dlatikay I like the sound of your Timer idea. I'll try to have the code in each event only run if a "Check" Boolean is true, and can have this Boolean switch between true and false on a timer, to see if this gives the desired results.Timms
How many controls are we talking about?Systematology
@Systematology A 17x10 Grid of them, which have been created within the code as opposed to in Design.Timms
issue comes into play when the user tries to hover over a distant tile. Something tells me we need to see this code in order to solve the real issue you have.Systematology
For additional context, this is within a basic game project. I'm aware that VB is pretty sub-optimal for such a use, but it's what I've got to use for this.Timms
@dlatikay It's not a system wide setting. It has been set in NativeMethods.TRACKMOUSEEVENT to 100 milliseconds.Wrung
W
4

I've posted the C# version of the answer here with a bit more details.


Note: The answer doesn't claim to solve the performance issue which you shared in the question, but shows how you can increase the mouse hover delay time.

The hover time has been set in NativeMethods.TRACKMOUSEEVENT to 100 milliseconds.

You can handle WM_MOUSEMOVE and call TrackMouseEvent by setting desired timeout for mouse hover as dwHoverTime field of the TRACKMOUSEEVENT. Also handle WM_MOUSEHOVER and raise a custom event like MyMouseHover, then you can subscribe for MyMouseHover event. You can find a similar approach in my post for handling hover event on title bar of a form: Handle Mouse Hover on Titlebar of Form.

VB.NET - Hover event with custom hover time

Her is an example of a control which raises MyMouseHover event with 500 ms delay:

Imports System
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Public Class SampleControl
    Inherits Control
    <DllImport("user32.dll")>
    Private Shared Function TrackMouseEvent(ByRef lpEventTrack As TRACK_MOUSE_EVENT) _
        As Integer
    End Function
    <StructLayout(LayoutKind.Sequential)>
    Private Structure TRACK_MOUSE_EVENT
        Public cbSize As UInteger
        Public dwFlags As UInteger
        Public hwndTrack As IntPtr
        Public dwHoverTime As UInteger
        Public Shared ReadOnly Empty As TRACK_MOUSE_EVENT
    End Structure
    Private track As TRACK_MOUSE_EVENT = TRACK_MOUSE_EVENT.Empty
    Const WM_MOUSEMOVE As Integer = &H200
    Const WM_MOUSEHOVER As Integer = &H2A1
    Const TME_HOVER As Integer = &H1
    Const TME_LEAVE As Integer = &H2
    Public Event MyMouseHover As EventHandler
    Protected Overrides Sub WndProc(ByRef m As Message)
        If m.Msg = WM_MOUSEMOVE Then
            track.hwndTrack = Me.Handle
            track.cbSize = CUInt(Marshal.SizeOf(track))
            track.dwFlags = TME_HOVER Or TME_LEAVE
            track.dwHoverTime = 500
            TrackMouseEvent(track)
        End If
        If m.Msg = WM_MOUSEHOVER Then
            RaiseEvent MyMouseHover(Me, EventArgs.Empty)
        End If
        MyBase.WndProc(m)
    End Sub
End Class
Wrung answered 7/2, 2019 at 20:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.