移动鼠标阻止WM_TIMER和WM_PAINT

时间:2014-02-26 11:06:21

标签: winapi mfc

在我正在处理的应用程序中,在某些情况下应用程序运行得非常慢,在这些情况下我发现我的移动鼠标,定时器/绘制消息没有被处理。如果我以慢圈移动鼠标,我可以无限期地阻止窗口被重新绘制!

我发现这是expected behaviour

  

除了WM_PAINT消息,WM_TIMER消息和   在WM_QUIT消息中,系统总是在a结束时发布消息   消息队列。这可确保窗口接收其输入消息   在正确的先进先出(FIFO)序列中。 WM_PAINT   但是,消息,WM_TIMER消息和WM_QUIT消息是   保留在队列中并仅在转发到窗口过程时   队列不包含其他消息。另外,还有多个WM_PAINT   同一窗口的消息组合成一个WM_PAINT   消息,将客户区的所有无效部分合并到一个   单一区域。组合WM_PAINT消息减少了a的次数   窗口必须重绘其客户区的内容。

但是,我该怎么办呢?有时直接响应鼠标移动,我需要尽快重新绘画。

我在CWnd派生类中通过这样的方法捕获消息:

virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);

2 个答案:

答案 0 :(得分:3)

正如您在文档中所读到的那样,WM_PAINTWM_TIMER与其他消息不同。

实际差异在于它们是最低优先级消息。也就是说,如果队列中还有其他消息,则不会处理它们。

那就是说,你正在移动鼠标,因此发布了很多消息,但是这些消息的频率通常很低(几秒钟几十),所以你的程序应该大部分都是空闲的,但它不是,可能是因为这些消息中的一些消耗的时间远远超过预期,并且正在阻塞队列。你只需要检测哪一个以及为什么。

一些鼠标相关的消息,我不在乎:

  • WM_MOUSEMOVE
  • WM_NCMOUSEMOVE
  • WM_SETCURSOR
  • WM_NCHITTEST

通过网络搜索:

  • WM_MOUSEOVER
  • WM_MOUSELEAVE
  • WM_NCMOUSEOVER
  • WM_NCMOUSELEAVE

无论如何,如果你想立即重新粉刷,而不是等待WM_PAINT,你应该致电UpdateWindow()。此函数强制立即处理WM_PAINT(如果有任何无效的东西),并阻塞直到它完成,绕过该消息的低优先级问题。

更新:根据您的评论中的情况,我认为您的最佳解决方案可能就是这样:

  1. WM_MOUSEMOVE中将光标位置保存在成员变量中并设置一个标志,表示鼠标已移动。
  2. 实现检查鼠标移动标志的OnIdle()处理程序。如果不移动,什么也不做。如果被移动,则进行昂贵的计算。
  3. 您可以在UpdateWindow()调用OnIdle()或不调用OnIdle()的情况下尝试使用,并查看哪个更好。
  4. 是的,在慢速计算机中它仍会感觉不稳定,但由于WM_TIMER的优先级甚至低于WM_PAINT和{{1}},因此这些消息不会无限期降级。更重要的是,您不会将多次调用排入昂贵的函数。

答案 1 :(得分:1)

几乎在所有情况下,正确的解决方案是当您更新应用程序状态以响应WM_MOUSEMOVE时需要重新绘制,您应该调用UpdateWindow()。这就对了。你不应该使用PeekMessage(),GetCursorPos,OnIdle()等。

如果你调用UpdateWindow(),那么将强制WM_PAINT消息,你的窗口将被更新,用户将看到他们的鼠标移动的反应,你的应用程序将感觉到响应。这很好。事实上,这是理想的。

如果不调用UpdateWindow(),则在传递WM_PAINT消息之前可能会出现另一条鼠标消息。大多数鼠标可以以128 / s的速度传送WM_MOUSEMOVE消息,触摸屏似乎以200 / s的速度运行,游戏鼠标可能更快。因此,如果用户快速移动鼠标,则WM_PAINT消息可能永远不会被强制传递。这使您处于每秒处理100多条WM_MOUSEMOVE消息但从不绘制窗口的情况。这意味着您的内部帧速率为100 fps,可见帧速率为0 fps。碎。

因此,再一次,答案是在需要绘制的WM_MOUSEMOVE处理之后调用UpdateWindow()。您的内部帧率可能较低(因为现在您为每条消息执行了更多工作),但您的可见帧率现在将与您的内部帧率相匹配,并且您的可见帧率很重要。

http://blogs.msdn.com/b/oldnewthing/archive/2003/10/01/55108.aspx

所述,将悄悄地丢弃额外的WM_MOUSEMOVE消息

我已经为许多应用程序做了这个修复,结果总是非常壮观。这种单行修复经常使应用程序的响应速度提高10倍。