在MFC中,窗口的绘制要至少要有两个必备的过程,首先是擦除,其次才是绘制。
你可以随便创建一个MFC应用程序,同时添加WM_PAINT和WM_ERASEBKGND 两个消息响应函数,调试一下你会发现首先响应的是擦除消息。因为,清空帧缓存总是比重新绘制它要快。
因此,检验窗口上能不能绘制像素首先要考虑擦除这个过程。因为,没有擦除,将不会正确的绘制。
WNDCLASS中的成员hbrBackground设置了窗口用于擦除背景的颜色值。如果该值取0,则意味着系统不为应用程序执行窗口擦除操作。
按照楼主说的方法创建工程,并调试跟踪,如下序列:
从APP的ProcessShellCommand(cmdInfo)开始往下走
AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL)
_AfxDispatchCmdMsg(。。。。)
CreateNewFrame(pDocument, NULL)
LoadFrame(。。。。。) // CFrameWnd
在上面这个函数中有
LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);
该调用是返回一个WNDCLASS名,用于在创建窗口时使用。
其值为:Afx:4000000:b:10011:6:145b06cd
MFC为向导生成的窗口定义的窗口类名规范有如下形式:
Afx:%x:%x:%x:%x:%x
其中每个&x代表以下参数的值:
WNDCLASS.hInstance
WNDCLASS.style
WNDCLASS.hCursor
WNDCLASS.hbrBackground
WNDCLASS.hIcon
对应可以看出在当前这个程序中hbrBackground 的值为系统颜色COLOR_WINDOW,不为零。也就是说,系统为窗口要执行擦除操作,擦除的颜色是COLOR_WINDOW。
那么为什么会出现楼主说的现象呢?
我们知道,该程序支持文档/视图模型,也就是框架的客户区由视图填充,可能的情况是,当存在一个活动视图时,框架窗口的擦除被视图所取代了。
为此,跟踪主窗口对象的消息响应函数OnEraseBkgnd
在该函数中,该响应函数调用的是其基类的OnEraseBkgnd,进入到CFrameWnd类中的OnEraseBkgnd我们可以看到如下实现:
BOOL CFrameWnd::OnEraseBkgnd(CDC* pDC)
{
if (m_pViewActive != NULL)
return TRUE; // active view will erase/paint itself
// for view-less frame just use the default background fill
return CWnd::OnEraseBkgnd(pDC);
}
从注释我们可以看出当存在一个激活的视图时,窗口的擦除与绘制是由视图完成的。否则,才会由系统完成。因此,当前程序有视图,并且虽然关闭了,但仍生于激活状态。因此,不会调用系统的擦除,但又由于关闭的窗口并没有被清除,只是其矩形区域大小为0而已,因此,视图所占的那部分的窗口就成了真空的,没有谁去在那里执行擦除和绘制操作,从而导致了楼主所说的现象。
在这里我顺便跟踪了一下CWnd::OnEraseBkgnd(pDC);发现最终调用的是WIN32API的 ::CallWindowProc(m_pfnSuper, m_hWnd, nMsg, wParam, lParam)函数,其中m_pfnSuper指的是该窗口的父窗口的窗口处理函数,由于框架窗口的父窗口是桌面窗口,因此,一般情况下的擦除是由桌面窗口来处理的。
这是我的一点浅见,请路过的高人多指教。
参考:MFC源码 MSDN