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

时间:2011-01-27 09:31:29

标签: vb.net winforms mouseevent wndproc mouseclick-event

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

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

也许通过截取窗口的WndProc或其他东西?

2 个答案:

答案 0 :(得分:6)

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

事实证明,Raymond Chen(Windows Shell团队的开发人员)在一篇名为“Logical consequences of the way Windows converts single-clicks into double-clicks”的博客文章中解释了这一点。

具体来说,Windows只知道将某些内容解释为双击,因为在GetDoubleClickTime function指定的时间间隔内发生了第二次点击。因为它需要透视(如Raymond所说的那样雄辩地说),如果要点击一次或双击,确定提前时间,窗口管理器继续发送WM_LBUTTONDOWN message收到第一次点击后立即WM_LBUTTONDBLCLK message仅在确认第二次点击后实际表示双击后才发送。结果是,您的应用程序将始终收到两条 WM_LBUTTONDOWN消息,用于收到的每封WM_LBUTTONDBLCLK消息。

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

  

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

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

  

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

     

嗯,你可以做的一件事就是在收到WM_LBUTTONDOWN消息时什么都不做,除了设置一个定时器在GetDoubleClickTime()毫秒内触发。 [已修正上午10点。]如果您在该时间内收到WM_LBUTTONDBLCLK条消息,那么毕竟是双击。如果你不这样做,那么它必须只需单击一下,这样你就可以进行单击操作(虽然有点迟了)。

答案 1 :(得分:4)

以下是执行您所要求的代码。

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

此代码的关键是延迟触发click事件,直到双击时间结束。如果在该时间内,在该时间内发生另一个单击事件,则在不调用click事件的情况下调用双击事件。但是,如果没有双击,则会调用click事件。

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