拦截单击或双击鼠标 - 仅在双击时执行双击代码

发布于 2024-10-14 05:52:58 字数 155 浏览 3 评论 0原文

我遇到的情况是,我同时处理单身和单身人士。窗体上的双击鼠标事件。在这两种情况下都必须加载某些内容,但是当发生双击时,我不希望执行附加到单击事件的代码。

有没有办法拦截鼠标单击并检查是双击还是单击,然后适当地执行正确的事件?

也许通过拦截窗口的WndProc什么的?

I have a situation where I am handling both single & double mouse click events on a form. In both cases something has to be loaded, however when a double click occurs, I do not wish to execute the code attached to the single click event.

Is there a way to intercept the mouse click's and check if double or single and then execute the right event appropriately?

Perhaps by intercepting the WndProc of the window or something?

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

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

发布评论

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

评论(2

蓝色星空 2024-10-21 05:52:58

不,除非您有时间机器,否则这几乎是不可能的。一旦您了解 Windows 如何区分双击和单击,它就变得毫无意义了。

事实证明,Raymond Chen(Windows Shell 团队的开发人员)在标题为“Windows 将单击转换为双击的逻辑结果"。

具体来说,Windows 只知道将某些内容解释为双击,因为在 GetDoubleClickTime 函数。因为它需要千里眼(正如雷蒙德如此雄辩地指出的那样)来提前确定某件事是单击还是双击,所以窗口管理器会继续发送一个 WM_LBUTTONDOWN 消息 一旦收到第一次点击。 WM_LBUTTONDBLCLK 消息仅稍后发送,确认第二次单击实际上代表双击后。结果是,对于收到的每条 WM_LBUTTONDBLCLK 消息,您的应用程序将始终收到两条 WM_LBUTTONDOWN 消息。

现在,.NET Framework 设计人员了解了此过程的工作原理并设计了相应引发的事件。当然,他们无法对双击之前总是发生的单击执行任何操作,但如果确定用户希望将其作为双击事件的一部分,则他们能够抑制第二次单击消息。作为 Control.MouseClick 的文档 事件(大致对应于WM_LBUTTONDOWN 消息)告诉我们:

根据用户操作系统的鼠标设置确定,在时间上足够接近的两次单击将生成 MouseDoubleClick 事件,而不是第二个 MouseClick 事件.

然而,我上面链接的雷蒙德的博客文章确实为坚持双击操作与单击操作无关的设计的应用程序和开发人员提出了一种可能的解决方法(尽管我们都不建议您实际这样做) ):

现在假设您是一个程序,但仍希望继续采用双击操作与单击操作无关的可疑设计。你做什么?

嗯,您可以做的一件事是,除了在 GetDoubleClickTime() 毫秒。 [已于上午 10 点更正。] 如果您在这段时间内收到 WM_LBUTTONDBLCLK 消息,那么这毕竟是双击。如果不这样做,那么一定是单击了一次,因此您可以执行单击操作(尽管有点晚了)。

No, that's pretty much impossible unless you have a time machine. And it doesn't really even make sense once you understand how Windows distinguishes double-clicks from single-clicks.

It turns out that Raymond Chen (a developer on the Windows Shell team) explains exactly that in a blog entry titled "Logical consequences of the way Windows converts single-clicks into double-clicks".

Specifically, Windows only knows to interpret something as a double-click because a second click has occurred within the interval specified by the GetDoubleClickTime function. Because it would require clairvoyance (as Raymond so eloquently puts it) to determine ahead of time if something is going to be a single or double click, the window manager goes ahead and sends a WM_LBUTTONDOWN message as soon as the first click is received. The WM_LBUTTONDBLCLK message is only sent later, after the second click is confirmed to actually represent a double-click. The upshot is that your application will always receive two WM_LBUTTONDOWN messages for each WM_LBUTTONDBLCLK message that is received.

Now, the .NET Framework designers understood how this process works and designed the events that are raised accordingly. Of course, they can't do anything about a single click always occurring before a double-click, but they were able to suppress the second click message if it is determined that the user intended that to be part of a double-click event. As the documentation for the Control.MouseClick event (which roughly corresponds to the WM_LBUTTONDOWN message) tells us:

Two single clicks that occur close enough in time, as determined by the mouse settings of the user's operating system, will generate a MouseDoubleClick event instead of the second MouseClick event.

Raymond's blog article that I linked to above does, however, propose a possible workaround for apps and developers who insist on a design where the double-click action is unrelated to the single-click action (although neither of us recommend that you actually do this):

Now suppose you're a program that nevertheless wants to continue with the dubious design of having the double-click action be unrelated to the single-click action. What do you do?

Well, one thing you could do is to do nothing on receipt of the WM_LBUTTONDOWN message aside from set a timer to fire in GetDoubleClickTime() milliseconds. [Corrected 10am.] If you get a WM_LBUTTONDBLCLK message within that time, then it was a double-click after all. If you don't, then it must have been a single-click, so you can do your single-click action (although a bit late).

空城旧梦 2024-10-21 05:52:58

这是执行您请求的代码。

Public Class Form1
    Const WM_LBUTTONDOWN As Integer = &H201
    Const WM_LBUTTONDBLCLK As Integer = &H203

    Private WithEvents tmrDoubleClicks As Timer

    Dim isDblClk As Boolean
    Dim firstClickTime As Date
    Dim doubleClickInterval As Integer

    Sub New()

        ' This call is required by the designer.
        InitializeComponent()
        tmrDoubleClicks = New Timer

        ' Add any initialization after the InitializeComponent() call.
        tmrDoubleClicks.Interval = 50
        doubleClickInterval = CInt(Val(Microsoft.Win32.Registry.CurrentUser.
                                       OpenSubKey("Control Panel\Mouse").
                                       GetValue("DoubleClickSpeed", 1000)))
    End Sub

    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                components.Dispose()
            End If
            If disposing AndAlso tmrDoubleClicks IsNot Nothing Then
                tmrDoubleClicks.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        Select Case m.Msg
            Case WM_LBUTTONDOWN
                If Not isDblClk Then
                    firstClickTime = Now
                    tmrDoubleClicks.Start()
                End If

            Case WM_LBUTTONDBLCLK
                isDblClk = True
                tmrDoubleClicks.Stop()
                DoubleClickActivity()
                isDblClk = False

            Case Else
                MyBase.WndProc(m)
        End Select
    End Sub

    Private Sub DoubleClickActivity()
        'implement double click activity here
        Dim r As New Random(Now.TimeOfDay.Seconds)
        Me.BackColor = Color.FromArgb(r.Next(0, 255), 
                                      r.Next(0, 255), 
                                      r.Next(0, 255))
    End Sub

    Private Sub SingleClickActivity()
        'implement single click activity here
        Beep()
    End Sub

    Private Sub tmrDoubleClicks_Tick(ByVal sender As Object, 
                                     ByVal e As System.EventArgs 
                                    ) Handles tmrDoubleClicks.Tick

        If Now.Subtract(firstClickTime).TotalMilliseconds > 
          doubleClickInterval Then

            'since there was no other click within the doubleclick speed,
            'stop waiting and fire the single click activity
            isDblClk = False
            tmrDoubleClicks.Stop()
            SingleClickActivity()
        End If
    End Sub
End Class

此代码的关键是延迟触发单击事件,直到双击时间过去。如果在该时间内,另一个点击事件发生,则调用双击事件,而不调用点击事件。但是,如果没有双击,则会调用单击事件。

这种延迟在双击速度较长的计算机上尤其明显。在典型的计算机上,双击速度为 500 毫秒,因此代码将在单击发生后 500 毫秒到 600 毫秒之间运行单击事件。

Here is code to do what you requested.

Public Class Form1
    Const WM_LBUTTONDOWN As Integer = &H201
    Const WM_LBUTTONDBLCLK As Integer = &H203

    Private WithEvents tmrDoubleClicks As Timer

    Dim isDblClk As Boolean
    Dim firstClickTime As Date
    Dim doubleClickInterval As Integer

    Sub New()

        ' This call is required by the designer.
        InitializeComponent()
        tmrDoubleClicks = New Timer

        ' Add any initialization after the InitializeComponent() call.
        tmrDoubleClicks.Interval = 50
        doubleClickInterval = CInt(Val(Microsoft.Win32.Registry.CurrentUser.
                                       OpenSubKey("Control Panel\Mouse").
                                       GetValue("DoubleClickSpeed", 1000)))
    End Sub

    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                components.Dispose()
            End If
            If disposing AndAlso tmrDoubleClicks IsNot Nothing Then
                tmrDoubleClicks.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        Select Case m.Msg
            Case WM_LBUTTONDOWN
                If Not isDblClk Then
                    firstClickTime = Now
                    tmrDoubleClicks.Start()
                End If

            Case WM_LBUTTONDBLCLK
                isDblClk = True
                tmrDoubleClicks.Stop()
                DoubleClickActivity()
                isDblClk = False

            Case Else
                MyBase.WndProc(m)
        End Select
    End Sub

    Private Sub DoubleClickActivity()
        'implement double click activity here
        Dim r As New Random(Now.TimeOfDay.Seconds)
        Me.BackColor = Color.FromArgb(r.Next(0, 255), 
                                      r.Next(0, 255), 
                                      r.Next(0, 255))
    End Sub

    Private Sub SingleClickActivity()
        'implement single click activity here
        Beep()
    End Sub

    Private Sub tmrDoubleClicks_Tick(ByVal sender As Object, 
                                     ByVal e As System.EventArgs 
                                    ) Handles tmrDoubleClicks.Tick

        If Now.Subtract(firstClickTime).TotalMilliseconds > 
          doubleClickInterval Then

            'since there was no other click within the doubleclick speed,
            'stop waiting and fire the single click activity
            isDblClk = False
            tmrDoubleClicks.Stop()
            SingleClickActivity()
        End If
    End Sub
End Class

The crux of this code is to delay firing the click event till the double click time elapses. If within that time, another click event occurs within that time, the double click event is called without calling the click event. If, however, there is no double click, the click event is called.

This delay is particularly noticeable on computers that have a longer double click speed. On a typical computer, the double click speed is 500ms so the code will run the click event somewhere between 500ms and 600ms after a click occured.

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