1.简介
WM_CREATE是windows中一个窗口消息。当一个应用程序通过CreateWindowEx函数或者CreateWindow函数请求创建窗口时发送此消息,产生时间是窗口创建之后显示之前,同时WM_CREATE也必须是不进队列消息,(此消息在函数返回之前发送),此消息类似于SendMessage()所发送的消息。
2.简化
以下对WindowImplBase的OnCreate()函数(即WM_CREATE消息处理函数)进行简化,简化后如下:
LRESULT WindowImplBase::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
//将窗口设置为无标题栏的:WS_CAPTION
//.......
//重新调整窗口位置,将窗口移动到原来窗口的客户区位置处
//.......
m_PaintManager.Init(m_hWnd);
m_PaintManager.AddPreMessageFilter(this);
//获取并设置窗口文字及图片等资源的位置
//.......
m_PaintManager.SetResourcePath(strResourcePath.GetData());
//解析资源,并将其中的布局xml解析成CControlUI树结构
//.......
CControlUI* pRoot = builder.Create(GetSkinFile().GetData(), (UINT)0, this, m_PaintManager);
m_PaintManager.AttachDialog(pRoot);
m_PaintManager.AddNotifier(this);
m_PaintManager.SetBackgroundTransparent(TRUE);//设置背景透明
InitWindow();//此函数为虚函数,想在窗口初始化干的事情可在该函数中实现
return 0;
}
3.分解
注意上述函数的几个重要步骤(其中m_PaintManager为WindowImplBase的成员变量):
- m_PaintManager.Init(m_hWnd);
- m_PaintManager.AddPreMessageFilter(this);
- m_PaintManager.AttachDialog(pRoot);
- m_PaintManager.AddNotifier(this);
下面需要对上述四个函数进行解析
3.1 函数 Init()
void CPaintManagerUI::Init(HWND hWnd)
{
ASSERT(::IsWindow(hWnd));
// Remember the window context we came from
m_hWndPaint = hWnd;
m_hDcPaint = ::GetDC(hWnd);
// We'll want to filter messages globally too
m_aPreMessages.Add(this);
}
其中 m_aPreMessages 为静态成员变量,在以下函数中被用到(可以猜测以下为静态函数):
//设置颜色时,用于循环刷新界面
void CPaintManagerUI::SetHSL(bool bUseHSL, short H, short S, short L)
{
//.......
for( int i = 0; i < m_aPreMessages.GetSize(); i++ )
{
CPaintManagerUI* pManager = static_cast<CPaintManagerUI*>(m_aPreMessages[i]);
if( pManager != NULL && pManager->GetRoot() != NULL )
pManager->GetRoot()->Invalidate();
}
}
//换肤,循环重新加载图片资源
void CPaintManagerUI::ReloadSkin()
{
for( int i = 0; i < m_aPreMessages.GetSize(); i++ )
{
CPaintManagerUI* pManager = static_cast<CPaintManagerUI*>(m_aPreMessages[i]);
pManager->ReloadAllImages();
}
}
//CPaintManagerUI对消息进行提前处理
//该函数在void CPaintManagerUI::MessageLoop()中调用(此函数为进程的消息循环)
bool CPaintManagerUI::TranslateMessage(const LPMSG pMsg)
{
//1.当窗口有父窗口时,循环搜索当前的hwnd所以对应的窗口或其长辈窗口(父窗口、祖父窗口);
//2.当窗口无父窗口时,循环搜索当前的hwnd所以对应的窗口;
//如果找到,则处理;否则直接返回false
CPaintManagerUI* pT = static_cast<CPaintManagerUI*>(m_aPreMessages[i]);
if (pT->TranslateAccelerator(pMsg))
return true;
if( pT->PreMessageHandler(pMsg->message, pMsg->wParam, pMsg->lParam, lRes) )
return true;
return false;
}
3.2 函数 AddPreMessageFilter()
bool CPaintManagerUI::AddPreMessageFilter(IMessageFilterUI* pFilter)
{
ASSERT(m_aPreMessageFilters.Find(pFilter)<0);
return m_aPreMessageFilters.Add(pFilter);
}
其中 m_aPreMessageFilters 为非静态成员变量,在以下函数中被用到:
//消息的提前处理
//在bool CPaintManagerUI::TranslateMessage(const LPMSG pMsg)函数中被调用
bool CPaintManagerUI::PreMessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& /*lRes*/)
{
for( int i = 0; i < m_aPreMessageFilters.GetSize(); i++ )
{
bool bHandled = false;
LRESULT lResult = static_cast<IMessageFilterUI*>(m_aPreMessageFilters[i])->MessageHandler(uMsg, wParam, lParam, bHandled);
if( bHandled )
{
return true;
}
}
switch( uMsg )
{
case WM_KEYDOWN:
case WM_SYSCHAR:
case WM_SYSKEYDOWN:
}
return false;
}
3.3 函数 AttachDialog()
bool CPaintManagerUI::AttachDialog(CControlUI* pControl)
{
//......
//删除原来的控件树结构,重设控件树
if( m_pRoot != NULL )
{
m_aPostPaintControls.Empty();
AddDelayedCleanup(m_pRoot);
}
m_pRoot = pControl;
//......
//初始化控件
return InitControls(pControl);
}
其中InitControls()的具体实现如下:
bool CPaintManagerUI::InitControls(CControlUI* pControl, CControlUI* pParent /*= NULL*/)
{
ASSERT(pControl);
if( pControl == NULL )
return false;
//重要、重要、重要
pControl->SetManager(this, pParent != NULL ? pParent : pControl->GetParent(), true);
pControl->FindControl(__FindControlFromNameHash, this, UIFIND_ALL);
return true;
}
3.4 函数 AddNotifier()
bool CPaintManagerUI::AddNotifier(INotifyUI* pNotifier)
{
ASSERT(m_aNotifiers.Find(pNotifier)<0);
return m_aNotifiers.Add(pNotifier);
}
其中 m_aNotifiers 为非静态成员变量,在以下函数中被用到:
bool CPaintManagerUI::MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lRes)
{
TNotifyUI* pMsg = NULL;
while( pMsg = static_cast<TNotifyUI*>(m_aAsyncNotify.GetAt(0)) )
{
m_aAsyncNotify.Remove(0);
if( pMsg->pSender != NULL )
{
if( pMsg->pSender->OnNotify ) pMsg->pSender->OnNotify(pMsg);
}
for( int j = 0; j < m_aNotifiers.GetSize(); j++ )
{
static_cast<INotifyUI*>(m_aNotifiers[j])->Notify(*pMsg);
}
delete pMsg;
}
// Cycle through listeners
for( int i = 0; i < m_aMessageFilters.GetSize(); i++ )
{
bool bHandled = false;
LRESULT lResult = static_cast<IMessageFilterUI*>(m_aMessageFilters[i])->MessageHandler(uMsg, wParam, lParam, bHandled);
if( bHandled )
{
lRes = lResult;
return true;
}
}
// Custom handling of events
switch( uMsg )
{
case WM_APP + 1:
case WM_CLOSE:
case WM_ERASEBKGND:
case WM_PAINT: //重要,负责绘制窗口中的各个控件
....
}
pMsg = NULL;
while( pMsg = static_cast<TNotifyUI*>(m_aAsyncNotify.GetAt(0)) )
{
m_aAsyncNotify.Remove(0);
if( pMsg->pSender != NULL )
{
if( pMsg->pSender->OnNotify ) pMsg->pSender->OnNotify(pMsg);
}
for( int j = 0; j < m_aNotifiers.GetSize(); j++ )
{
static_cast<INotifyUI*>(m_aNotifiers[j])->Notify(*pMsg);
}
delete pMsg;
}
return false;
}
3.5 小结
//初始化PaintManager的句柄及画笔
//在PaintManager的静态成员变量中注册该窗口,在消息循环、换肤等中使用
- m_PaintManager.Init(m_hWnd);
//注册该窗口,就可以调用该窗口的MessageHandler函数了
- m_PaintManager.AddPreMessageFilter(this);
//为窗口设置控件树,并初始化各个控件
//控件的绘制与此PaintManager种的画笔有很大关系
- m_PaintManager.AttachDialog(pRoot);
//注册上了Notify()函数,供PaintManager中的MessageHandler()函数调用
//PaintManager的MessageHandler()处理系统的各种消息,自己窗口不处理的消息均由此处理
- m_PaintManager.AddNotifier(this);
4.总结
NOTHING, END