MFC GUI自定义控件:如何绘制光标更新以响应鼠标移动?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MFC GUI自定义控件:如何绘制光标更新以响应鼠标移动?相关的知识,希望对你有一定的参考价值。

我有一个来自CButton的自定义Windows控件(不知道为什么选择了这个 - 这是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()方法最终将被告知这些区域无效,而不是完全重新绘制它可能只是从坐标它们是哪个单元格(不是简单的操作btw)并重新绘制它们,这样不仅可以简化这个光标问题,而且还可以确保只有少数单元格被绘制,部分遮挡的控件部分显示出来。但时间压力不允许,用例似乎没有要求优化。

所以问题是:是否有一些很好的方法让OnMouseMove()立即重新渲染一个控件,如果有的话,DC是什么? (例如,我可以通过DC缓存我在DrawItem()收到的FromHandle()?

现在我唯一的想法就是让一个对象成员指向要重绘的单个单元格,使用此RDW_UPDATENOW标志调用RedrawWindow(),并使用DrawItem(),如果设置了该标志,则只执行该项目。这将导致DrawItem()得到一个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,并且通常可以在不改变的情况下重复使用。

以上是关于MFC GUI自定义控件:如何绘制光标更新以响应鼠标移动?的主要内容,如果未能解决你的问题,请参考以下文章

MFC 自定义 OnPaint 未被可靠调用

WPF中的自定义光标?

MFC编程的时候,改变鼠标光标样式

MFC中如何让静态控件响应鼠标移动的消息?

MFC如何添加自定义控件

mfc 如何添加光标