您的位置 首页 > 数码极客

如何在mfc的ondraw()中调用其他函数

在MFC程序中绘制界面时,如果界面绘制工作比较久或界面结构比较复杂时,常常会出现闪烁的现象。原因有二:

1) MFC程序默认处理WM_ERASEBKGND消息时,会使用窗口类的画刷(通常是白色)将窗口背景擦除。

我们先来看看MSDN上关于WM_ERASEBKGND消息的说法:

WM_ERASEBKGND message

Sent when the window background must be erased (for example, when a window is resized). The message is sent to prepare an invalidated portion of a window for painting.

Parameters

wParam

A handle to the device context.

lParam

This parameter is not used.

Return value

Type: LRESULT

An application should return nonzero if it erases the background; otherwise, it should return zero.

Remarks

The DefWindowProc function erases the background by using the class background brush specified by the hbrBackground member of the WNDCLASS structure. If hbrBackground is NULL, the application should process the WM_ERASEBKGND message and erase the background.

An application should return nonzero in response to WM_ERASEBKGND if it processes the message and erases the background; this indicates that no further erasing is required. If the application returns zero, the window will remain marked for erasing. (Typically, this indicates that the fErase member of the PAINTSTRUCT structure will be TRUE.)

当窗口移动位置或者改变大小时,系统会发送此消息用于准备窗口移动位置或改变大小过程中出现的无效区域,接下来就是进入WM_PAINT处理流程对此无效区域进行实际的绘制了。

有了这个知识,我们就可以拦截此消息,直接返回TRUE,这样就绕开了系统的默认处理流程。注意,这里需要返回TRUE而不是FALSE,因为如果是FALSE,则表示此窗口还是标记为需要擦除。

2) 界面绘制直接在窗口DC上绘制,每一个GDI绘制操作都直接在界面上可见,这样的情况下,绘制任务一旦多起来,就不可避免的出现了闪烁。

如果启用双缓冲机制,则闪烁大大减小,甚至完全没有了闪烁。

原理如下:

创建一个新的DC,此DC存在于内存中,并且大小和窗口DC一样,绘制界面时,先将所有的GDI操作在此内存DC上进行,待全部绘制工作完成,使用BitBlt直接将内存DC上的内容拷贝到窗口DC上,这样批量化的处理,有助于减少频繁GDI操作带来的闪烁。

在CodeProject上有这样一篇文章,可以很好的演示双缓冲绘图的效果。这里,摘录其部分代码进行分析:

未启用双缓冲时绘制界面的代码如下:

这里在View的OnDraw方法中,直接在窗口DC上进行的绘制。

启用了双缓冲的代码:

作者定义了一个内存DC的对象,所有的绘制界面操作全部在内存DC上完成,经过比对,界面的闪烁完全消失了。

下面我们来看看作者的内存DC是如何实现的,以下代码为片段,用于说明原理:

在CMemDC2的构造函数中,首先调用CreateCompatibleDC创建一个兼容的内存DC,然后调用CBitMap对象的CreateCompatibleBitmap创建了一个和窗口DC一样大小的兼容位图,最后将兼容位图SelectObject到内存DC中。至此,一个内存DC构造完毕。界面绘制工作可以在此内存DC对象上进行了。

在CMemDC2的析构函数中,直接使用了BitBlt函数,将内存DC中的所有内容一次性的拷贝到窗口DC,所有我们在OnDraw方法中看到一个局部的CMemDC2的对象,因为在此局部对象离开作用域,析构函数自动调用,也就完成了DC内容的拷贝。注意,这里BitBlt完成后,需要使用SelectObject将原来的位图对象重新选入到DC中。

感谢作者为我们带来了这么优雅的一个内存DC!

责任编辑: 鲁达

1.内容基于多重复合算法人工智能语言模型创作,旨在以深度学习研究为目的传播信息知识,内容观点与本网站无关,反馈举报请
2.仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证;
3.本站属于非营利性站点无毒无广告,请读者放心使用!

“如何在mfc的ondraw()中调用其他函数”边界阅读