CDesktop类负责处理窗口们。当一个窗口CreateWin以后,再在Window上面Add一些Control,把它Add到CDesktop里面就算完事了。当然在Add之前可以酌情保留其指针方便控制,也可以用CDesktop类的FindWindow()函数查找指定Name的Window,返回其指针再对其操作。而绘制桌面窗口的时候只需把desktop变量的指针传递给CGraph的RenderDesktop()函数即可绘画出所有的窗口及其子控件。真是方便之极。难免自己要先陶醉一下。
在CDesktop里面,我用到了STL,标准模板库。
#include <list>
using namespace std;
用了其中的list容器,来保存add函数传递来的窗口句柄。
list<CWin*> m_pWinList;
每当传进新的窗口句柄,就把他压入list容器的前面. (push_front)。
m_pWinList.push_front(pNewWin);
先规范一下窗体处理的顺序问题。
一般来说,绘画窗体是按照窗体的ZOrder循序,处于最上层的窗口最后绘画,以遮盖下层的窗口。因此定义如下规则:
1. 最前的窗口处于list容器的前端( front, begin() )
2. 处理绘画函数从list容器的后端开始逐个窗体绘画.
// 绘画所有窗口
bool CDesktop::Draw(IDirectDrawSurface * lpDDS, LPRECT lpRect)
{
if ( m_pWinList.empty() )
return false;
m_pWinIterator = m_pWinList.end();
do {
// 遍历所有表内元素, 执行Draw
m_pWinIterator -- ;
(*m_pWinIterator)->Draw( lpDDS, lpRect );
} while ( m_pWinIterator != m_pWinList.begin() );
return true;
}
3. 处理消息函数从list容器的前端开始逐个测试传递.
因为把窗体初始化的代码单独拿了出来,所以要注意一个问题:
当切换全屏/窗口模式的时候,会释放掉旧的DirectDraw。那么旧的DirectDraw所建立的Surface同样会失效。所以,Desktop同样要在切换模式之前执行释放函数把所有的子窗体释放掉,待重新初始化DirectDraw后再重新初始化窗体。否则,窗体所保存的surface指针指向的将不会再是一个有效的DirectDrawSurface。这个问题花了我几乎一个小时去debug。得益于远程调试,两台机器并用能够一边看代码一边调试,否则切换成全屏就不能看到代码这个问题有排烦了。途中顺便也把之前提到可能的访问异常去掉了。原来CSurface没有把lpDDS初始化为NULL而使到释放宏不能判断指针的有效性,直接执行了一个无效的Release()操作。这是一个低级的错误,sigh。
好,继续完善。