【问题标题】:Detecting a single mouse click in MFC在 MFC 中检测单击鼠标
【发布时间】:2010-10-05 04:49:58
【问题描述】:
在 MFC 中,双击鼠标事件会触发以下消息序列
- WM_LBUTTONDOWN
- WM_LBUTTONUP
- WM_LBUTTONDBCLK
- WM_LBUTTONUP
因此响应 WM_LBUTTONDBCLK 消息可以让您检测到双击。但是如果我只是想检测单击如何区分呢?
但仅查看 WM_LBUTTONUP 消息是不够的,因为它可能是单击或双击的第一次单击。
我如何才能成功识别单击?
【问题讨论】:
标签:
user-interface
winapi
visual-c++
mfc
【解决方案1】:
我认为解决方案是在第一次单击后启动计时器,然后在下一次立即单击后检查经过的时间,这将告诉您是单击还是双击。
【解决方案2】:
(请允许我将这些事件称为 Mouse Up 和 Mouse Down。我的 MFC 有点生锈了。还有一个叫做 .NET 的东西最近弄乱了我的术语;-)
小故事:您不只是想了解鼠标点击。你需要更多。
长篇大论:
虽然这是违反直觉的,但似乎只是想要单击鼠标是相当少见的。大多数情况下,您需要在 Mouse Down 上执行一些处理并在 Mouse Up 上进行一些进一步的处理。诀窍是仅仅跟踪 Mouse Up 消息是不够的:Mouse Down 可能没有在您的窗口中发生。你认为这是一次有效的点击吗?特别是考虑到没有发生 Mouse Down 处理(例如选择一个项目)。
进一步推理,在处理鼠标按下后,您不应该依赖接收鼠标按下:用户可能已经移动了鼠标并在其他地方释放了按钮(想想拖放),在这种情况下,您不接收 MouseUp 事件...除非您在 MouseDown 上捕获鼠标以确保即使鼠标离开您的窗口也能将鼠标事件提升到 Mouse Up。
总而言之,您最终会跟踪 Mouse Down,捕获鼠标,当您收到 Mouse Up 时,只需检查您是否拥有捕获的所有权。如果没有,鼠标要么被双击(没有第二次按下鼠标),要么鼠标按下发生在其他地方,因此你很可能不关心这个鼠标按下。
结论:没有 MouseClick 消息只是因为您不会走得太远:您需要处理更多消息并实现更多机制。
哦!如果您正在处理已经处理所有这些项目和选择内容的现有控件,例如列表视图,它可能会提供类似的自定义通知,例如项目激活或项目选择已更改。
【解决方案3】:
我刚刚在 Delphi 中尝试过,行为是相同的:即使发生双击,单击事件也会在两者中的第一个之后立即发出。
我使用计时器解决了这个问题,它的工作原理如下:
- 停用 WM_LBUTTONDBLCLK 上的计时器(并将
bDbl 设置为 true)
- 如果
bDbl==false,则在 WM_LBUTTONUP 上激活计时器
- 如果
bDbl==true 则在 WM_LBUTTONUP 上停用(并重置 bDbl)
我将定时器的间隔设置为GetDoubleClickTime返回的时间。
MSDN 说:
GetDoubleClickTime 函数
检索当前的双击
鼠标的时间。双击是
一系列的两次点击鼠标
按钮,第二个发生在
第一次之后的指定时间。这
双击时间最长
可能发生的毫秒数
在第一次和第二次点击之间
双击。
如果计时器碰巧触发,那么您就有了真正的点击。在我的情况下,双击间隔是 500 毫秒,所以任何“真正的点击”都会延迟这么长时间。
【解决方案4】:
这有点棘手。
我会检测 WM_LBUTTONDOWN 和 WM_LBUTTONUP 组合,将该事件存储在某处并设置一秒钟左右的超时。如果在该超时期间没有 WM_LBUTTONDBCLK,那么您只需单击一下。
这可能意味着您需要运行另一个线程,但我认为您可以使用一个线程来完成它。
【解决方案5】:
您可以使用 PreTranslateMessage() 对出现的消息进行计数。如果您只收到与单击对应的鼠标消息,并且系统配置的双击时间已过期,您可以放心地认为它是单击。
据我所知,没有办法知道正在发生这种情况,这是有道理的 - 直到时间到期,没有办法知道第二次点击是否到来.
【解决方案6】:
您可以检查 WM_LBUTTONDOWN 在 WM_LBUTTONUP 之前是否被多次调用。实际上,Windows 会为您执行此操作,因为如果您获得 WM_LBUTTONDBCLK,您往往不会获得 WM_LBUTTONUP。
【解决方案7】:
您通常会查看@MLButtonUp,并且不会在同一个鼠标按钮上进行单击和双击行为。