我有一个自定义Windows控件,该控件从CButton
子类化(不知道为什么选择了它-这是17年的代码;没有按钮功能的外观)。DrawItem( LPDRAWITEMSTRUCT pdis )
响应CButton::OnChildNotify
调用其WM_DRAWITEM
方法。它使用DC CDC::FromHandle( pdis->hDC )
渲染其场景。
鼠标事件方法OnMouseMove()
计算新的光标位置并调用RedrawWindow( NULL, NULL, RDW_INVALIDATE )
。紧随鼠标之后的光标会出现在新的鼠标位置。它工作正常,但速度很慢。实际上,仅需要重绘以前的光标单元和新的光标单元(如果需要),而随着整个场景被渲染多次,图形更新就会开始滞后。
我认为在我的OnMouseMove()
方法中,无需重绘整个场景,而可以重绘所讨论的单元格。它已经具有单元格的精确X和Y坐标以及指向其数据的指针。我以为CPaintDC(this)
将提供允许使用此功能的DC
,但它不会绘制。 (也不会崩溃,这是一种难得的喜悦。)
我朦胧的回忆是,执行此操作的“最佳”方法将是仅使两个单元格的区域无效,而DrawItem()
方法最终将被告知这些区域无效,而不是完全重新粉刷它可以解决问题从坐标是它们所在的单元格(不是一个简单的操作)并重新绘制它们,这不仅可以简化此光标问题,而且可以确保部分遮盖的控件被部分显示,从而仅绘制了几个单元格。但是时间压力不允许,用例似乎并不要求对此进行优化。
因此,问题是:OnMouseMove()
是否有一些不错的方法可以立即重新呈现单个控件,如果是,则使用什么DC
? (例如,我可以通过DC
缓存在DrawItem()
中收到的FromHandle()?
吗?
现在,我唯一的想法是让一个对象成员指向要重绘的单个单元格,使用此RDW_UPDATENOW标志调用RedrawWindow(),并让DrawItem()(如果设置了该标志)仅执行一项。这将导致DrawItem()获得一个DC,该DC可能会一直使用。虽然看起来像是真正的黑客,还有更好的方法吗?
最佳答案
在Windows应用程序中,习惯于响应WM_PAINT
(或WM_NCPAINT
)消息执行所有渲染。需要触发重新绘制的代码通过调用InvalidateRect
(和朋友)将窗口的部分或全部客户区标记为脏区。系统针对这种方法进行了优化,将多个请求合并到一个更新区域中,然后在没有其他重要工作需要执行时(例如处理输入)发出WM_PAINT
消息。
这可靠地工作,并且通常比在多个地方分布渲染更容易实现。但是,偏离此位置并在代码中的任何位置执行渲染都是完全合法的。尽管WM_PAINT
消息仍然可以随时到达,但是希望带外渲染产生与WM_PAINT
处理程序相同的视觉结果,以防止出现视觉伪像。
所有渲染都通过称为device context(DC)的抽象进行。在MFC应用程序中处理WM_PAINT
消息时,可以通过构造CPaintDC
实例获得合适的DC。在其他任何地方渲染时,您不能使用CPaintDC
,而需要使用CClientDC
代替(或使用CWindowDC
来渲染非工作区)。通常,渲染代码不需要知道要渲染到哪种类型的DC,通常无需更改即可重复使用。