WM_PAINT源头:第一次创建窗口,窗口最大、最小化,窗口大小改变、窗口移动,无效区等动作,以及调用Invalidate、InvalidateRect或InvalidateRgn、Updateindow等函数。
每个窗口(HWND)实例,在windows操作系统中,都有个上下文记录区,其中记录着当前窗口的无效区域数据。系统内核利用空闲时间检查所有窗口的无效区,如果非空,就产生一个WM_PAINT发送给此线程再转发到当前窗口来处理。当然此时,此窗口的无效区域还是存在的,通过在WM_PAINT中执行BeginPaint,就将此无效区域清空(使用ValidateRect一样效果),在执行具体的绘制操作。(这些执行都在窗口的Default中执行了,MS不给你看具体的过程,所以在MFC的系统代码中看不到。)。如果不将无效区域清空,系统将周而复始的产生WM_PAINT消息,导致OnIdle不能被执行,且当前程序CPU占用差不多100%。(由于是空闲时间处理,所以对话框的其他消息处理没被阻塞,可以按按钮等操作)。
I、拖动窗口,将被全部重新绘制,因为拖动的操作调用了RedrawWindow函数,此函数不光产生整个窗口的 Invalide调用,同时接下来还直接执行窗口的绘制操作(读取窗口的无效区,如果不屏蔽CDialog::OnPaint,就在OnPaint里面绘制了)。
II、如果是被另外一个对话框覆盖,那个对话框将会向其下的窗口(默认的窗口Z轴顺序)发生设置无效区域的指令
相关函数简介:
InvalidateRect(hWnd,&rect,TRUE): 向hWnd窗体发出WM_PAINT的消息,强制客户区域重绘制,是通过线程的消息队列来发送刷新消息,是最常用的
Invalidate:标记一个需要重绘的无效区域,并不意味着调用该函数后就立刻进行重绘。只是放一个WM_PAINT消息在队列里,不做别的,所以只有当当前函数返回后,进入消息循环,取出WM_PAINT,才执行WM_PAINT.
UpdateWindow: 直接调用窗口函数立即响应刷新消息,使窗口刷新消息优先被响应(消息队列中如果没有WM_PAINT消息就什么都不执行),UpdateWindow()只向窗体发送WM_PAINT消息,在发送之前判断GetUpdateRect(hWnd,NULL,TRUE)看有无可绘制的客户区域,如果没有,则不发送WM_PAINT.一般是在ShowWindow之后调用。
RedrawWindow:
BOOL RedrawWindow( LPCRECT lpRectUpdate = NULL, CRgn* prgnUpdate = NULL, UINT flags = RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE );
根据fuRedraw旗标的设置,重画全部或部分窗口,相当于先调用InvalidateRect,紧接着又调用UpdateWindow,此外RedrawWindow还提供了一些前两者没法做到的功能。
附录A 设置窗口位置大小的2个函数:
I、void MoveWindow( int x, int y, int nWidth, int nHeight, BOOL bRepaint = TRUE );
II、
BOOL SetWindowPos( const CWnd* pWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags );
附录B:静态切分窗口:当窗口第一次被创建时,窗格就已经被切分了,窗格数目、次序不在改变。
I 重载函数OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext *pContext);
II 在里面添加窗口静态切分函数CreateStatic(CWnd*,int,int,DWORD,UINT);
III 为静态窗格指定一个视图类CreateView(int,col,CRuntimeClass*,SIZE,CCreateContext*);
例子:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext *pContext)
{
// TODO: Add your specialized code here and/or call the base class
CRect rect;
GetWindowRect(&rect);
BOOL bRes=m_wndSplitter.CreateStatic(this,2,1);
m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CBombAppView),CSize(rect.Width(),rect.Height()/10),pContext);
m_wndSplitter.CreateView(1,0,RUNTIME_CLASS(CBombAppView1),CSize(rect.Width(),rect.Height()),pContext);
// m_wndSplitter.SetColumnInfo(0,rect.Height()/2,10); //设置列长
// m_wndSplitter.SetColumnInfo(1,rect.Height()/2,10);
m_wndSplitter.RecalcLayout();
return bRes;
}
附录c http://hi.baidu.com/ouanan/blog/item/ad90dacf559dd13af9dc616b.html
http://baike.baidu.com/view/1226797.htm
http://baike.baidu.com/view/1226818.htm
http://www.cppblog.com/OnTheWay2008/archive/2009/06/03/86615.aspx
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/xiven/archive/2009/06/15/4271387.aspx