C++ MFC GUI自定义控件:如何绘制光标更新以响应鼠标移动?
我有一个自定义的Windows控件,它的子类来自C++ MFC GUI自定义控件:如何绘制光标更新以响应鼠标移动?,c++,windows,user-interface,mfc,C++,Windows,User Interface,Mfc,我有一个自定义的Windows控件,它的子类来自CButton(不知道为什么选择它——这是一个17年的代码;没有按钮功能的外观) 它的DrawItem(LPDRAWITEMSTRUCT pdis)方法由CButton::OnChildNotify调用,以响应WM\u DrawItem。它使用DC-CDC::FromHandle(pdis->hDC)渲染场景 鼠标事件方法OnMouseMove()计算新的光标位置并调用重画窗口(NULL、NULL、RDW\u INVALIDATE)。跟随鼠标的光标
CButton
(不知道为什么选择它——这是一个17年的代码;没有按钮功能的外观)
它的DrawItem(LPDRAWITEMSTRUCT pdis)
方法由CButton::OnChildNotify
调用,以响应WM\u DrawItem
。它使用DC-CDC::FromHandle(pdis->hDC)
渲染场景
鼠标事件方法OnMouseMove()
计算新的光标位置并调用重画窗口(NULL、NULL、RDW\u INVALIDATE)
。跟随鼠标的光标将适时出现在新的鼠标位置。它工作正常,但速度很慢。事实上,只有以前的和新的光标单元需要重新绘制(如果需要的话),但随着整个场景多次渲染,图形更新开始滞后
我认为在我的OnMouseMove()
方法中,不必重新绘制整个场景,只需绘制有问题的单元即可。它已经有了单元格的精确X和Y坐标以及指向其数据的指针。我以为CPaintDC(this)
会提供一个DC
,允许这样做,但它不能绘制。(也不会崩溃,这是一种难得的快乐。)
我模糊不清的回忆是,这样做的“最佳”方法是仅使两个单元格的区域无效,而DrawItem()
方法最终会被告知这些区域无效,而不是完全重新绘制,只需根据坐标计算出它们是哪些单元格(顺便说一句,这不是一个简单的操作)然后重新绘制它们,这不仅可以简化光标问题,而且还可以确保只有少数单元格在部分模糊的控件部分显示的情况下被绘制。但是时间压力是不允许的,用例似乎也不要求对此进行优化
所以问题是:有没有什么好方法可以让OnMouseMove()
立即重新呈现单个控件,如果有,用什么DC
?(例如,我可以通过FromHandle()?
缓存在DrawItem()
中收到的DC
现在我唯一的想法是让一个对象成员指向一个要重画的单元格,用这个RDW_UPDATENOW标志调用RedrawWindow(),并让DrawItem(),如果设置了这个标志,只做一个项目。这将导致DrawItem()获取一个DC,它可能会以它一贯的方式工作。这似乎是一个真正的黑客行为,但有更好的方法吗?在Windows应用程序中,通常会响应(或)消息执行所有渲染。需要触发重绘的代码会通过调用(和朋友)将Windows的部分或全部客户端区域标记为脏的。系统针对这种方法进行了优化,将多个请求合并到单个更新区域,然后在没有更重要的工作要做(如处理输入)时发出
WM_PAINT
消息
这工作可靠,通常比将渲染分散到多个位置更容易实现。但是,完全可以合法地偏离这一点,在代码中的任何位置执行渲染。尽管消息仍然可以随时到达,但最好让带外渲染产生相同的视景效果所有结果与WM_PAINT
处理程序一样,以防止视觉伪影
所有渲染都经过一个称为a(DC)的抽象。在MFC应用程序中处理
WM_PAINT
消息时,可以通过构造实例来获得合适的DC。在任何其他地方渲染时,都不能使用cpaitdc
,而需要使用a(或a,也可以渲染非客户端区域)。通常,渲染代码不需要知道它渲染到哪种类型的DC,并且通常可以在不做更改的情况下重复使用。在WM_PAINT
中,默认情况下将剪裁DC,以便仅允许在包围已失效区域的框中进行绘制。重画窗口()
使整个窗口无效。使用invalidate()
仅使实际需要重画的区域无效。不要依赖鼠标位置来决定要画什么。您可以使用GetClipBox()
获取DC的裁剪框,然后不要绘制框外的任何内容。使用框的坐标确定框内的单元格,然后仅绘制这些单元格。“对象只能在响应WM_PAINT
消息时使用”。当然,您不能在WM\u MOUSEMOVE
处理程序中使用它。您可以在WM\u MOUSEMOVE
处理程序中执行的操作是计算网格光标位置,调用您的实现进行设置,并让该实现更新上一个(如果有)与新单元格一样,如果网格光标位置与以前的网格光标位置不同,那么专门针对WM_PAINT
进行渲染的规则实际上是一个经验法则。在遵循规则时,不需要考虑太多。所有内容都可以有效地工作。您可以在WM_PAINT也一样,只要你的WM_PAINT
处理程序和带外渲染产生相同的视觉效果(如果它们不产生,你会得到闪烁、不一致的UI和混乱的用户)。如果你想响应WM_MOUSEMOVE
进行渲染,抓取一个图标并执行渲染(还原……以前高亮显示的单元格,并呈现新的高亮显示)。您可能希望应用适当的剪裁区域,但这不是严格要求的。您还必须确保注册消息,以便在控件外移动时还原高亮显示的单元格。