我有一个情况,需要在表单上处理单击和双击事件。在两种情况下都需要加载一些内容,但是当发生双击时,我不希望执行与单击事件相关的代码。
是否有一种方法可以拦截鼠标点击并检查是双击还是单击,然后适当地执行正确的事件?
也许通过拦截窗口的WndProc之类的方式可以实现?
我有一个情况,需要在表单上处理单击和双击事件。在两种情况下都需要加载一些内容,但是当发生双击时,我不希望执行与单击事件相关的代码。
是否有一种方法可以拦截鼠标点击并检查是双击还是单击,然后适当地执行正确的事件?
也许通过拦截窗口的WndProc之类的方式可以实现?
不,除非你有一台时间机器,否则这几乎是不可能的。 一旦你了解Windows如何区分双击和单击,这甚至没有任何意义。
事实证明,Windows Shell团队的开发人员Raymond Chen在一篇名为“Windows将单击转换为双击的逻辑后果”的博客文章中详细解释了这一点。
具体来说,Windows只有在GetDoubleClickTime
函数指定的时间间隔内发生第二次点击时才将其解释为双击。因为要提前确定某个操作是单击还是双击需要超人的洞察力(正如Raymond所说),窗口管理器会在接收到第一次点击时立即发送WM_LBUTTONDOWN
消息。只有在确认第二次点击确实代表双击后,才会稍后发送WM_LBUTTONDBLCLK
消息。总之,您的应用程序将始终接收每个接收到的WM_LBUTTONDBLCLK
消息的两个WM_LBUTTONDOWN
消息。Control.MouseClick
事件(大致对应于 WM_LBUTTONDOWN
消息)的文档所述:
我上面提到的 Raymond 的博客文章确实为那些坚持双击操作与单击操作无关的应用程序和开发人员提供了可能的解决方法(尽管我们都不建议您这样做)。如果两次单击的时间间隔足够接近(由用户操作系统的鼠标设置确定),则会生成一个
MouseDoubleClick
事件,而不是第二个MouseClick
事件。
GetDoubleClickTime()
毫秒后触发之外,什么也不做。 [更正于上午10点。]如果您在该时间内收到WM_LBUTTONDBLCLK消息,则它确实是双击。如果没有,则必须是单击,因此您可以执行单击操作(虽然有点晚)。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
Timer
对象,但从未调用过 Dispose
方法。这几乎让我想要给你一个踩下去的投票。 - Cody GrayDispose
方法放在 Form.Designer.vb 文件中(即设计器生成的代码所在的位置)。感谢您指出。 - Alex Essilfie