文章目录
1.OnCreate函数
- 1.OnCreate函数
- 2.作者答疑
有了前面对消息传递的详细讲解,接下来是duilib窗口的初始创建过程讲解。这个函数在窗口创建消息中调用,如下所示:
LRESULT WindowImplBase::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
// 调整窗口样式
LONG styleValue = ::GetWindowLong(*this, GWL_STYLE);
styleValue &= ~WS_CAPTION;
::SetWindowLong(*this, GWL_STYLE, styleValue | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
//WS_CLIPCHILDREN 窗口不对子窗口区域进行绘制。
//默认情况下父窗口会对子窗口背景是进行绘制的,但是如果父窗口设置了WS_CLIPCHILDREN属性,父亲窗口不在对子窗口背景绘制
//WS_CLIPSIBLINGS 控制子窗口重叠部分绘制
RECT rcClient;
::GetClientRect(*this, &rcClient);
::SetWindowPos(*this, NULL, rcClient.left, rcClient.top, rcClient.right - rcClient.left, \
rcClient.bottom - rcClient.top, SWP_FRAMECHANGED);
//SWP_FRAMECHANGED:给窗口发送WM_NCCALCSIZE消息,即使窗口尺寸没有改变也会发送该消息。如果未指定这个标志,只有在改变了窗口尺寸时才发送WM_NCCALCSIZE。
// 关联UI管理器
//初始化函数,清空CPaintManagerUI的状态,注册窗口接受drop信息,注册自己作为窗口的预处理对象
m_pm.Init(m_hWnd, GetManagerName());
// 注册PreMessage回调
m_pm.AddPreMessageFilter(this);
// 创建主窗口
CDialogBuilder builder;
if (m_pm.GetResourcePath().IsEmpty())
{ // 允许更灵活的资源路径定义
CDuiString strResourcePath = m_pm.GetInstancePath();
strResourcePath += GetSkinFolder().GetData();
m_pm.SetResourcePath(strResourcePath.GetData());
}
//根据资源类型进行合适初始化
switch (GetResourceType())
{
case UILIB_ZIP:
m_pm.SetResourceZip(GetZIPFileName().GetData(), true);
break;
case UILIB_ZIPRESOURCE:
{
HRSRC hResource = ::FindResource(m_pm.GetResourceDll(), GetResourceID(), _T("ZIPRES"));
if (hResource == NULL)
return 0L;
DWORD dwSize = 0;
HGLOBAL hGlobal = ::LoadResource(m_pm.GetResourceDll(), hResource);
if (hGlobal == NULL)
{
#if defined(WIN32) && !defined(UNDER_CE)
::FreeResource(hResource);
#endif
return 0L;
}
dwSize = ::SizeofResource(m_pm.GetResourceDll(), hResource);
if (dwSize == 0)
return 0L;
m_pm.SetResourceZip((LPBYTE)::LockResource(hGlobal), dwSize);
#if defined(WIN32) && !defined(UNDER_CE)
::FreeResource(hResource);
#endif
}
break;
}
//根据xml文件创建控件
CControlUI* pRoot = NULL;
if (GetResourceType() == UILIB_RESOURCE)
{
STRINGorID xml(_ttoi(GetSkinFile().GetData()));
pRoot = builder.Create(xml, _T("xml"), this, &m_pm);
}
else {
pRoot = builder.Create(GetSkinFile().GetData(), (UINT)0, this, &m_pm);
}
ASSERT(pRoot);
if (pRoot == NULL)
{
MessageBox(NULL, _T("加载资源文件失败"), _T("Duilib"), MB_OK | MB_ICONERROR);
ExitProcess(1);
return 0;
}
m_pm.AttachDialog(pRoot);//根控件绑定CPaintManagerUI对象
// 添加Notify事件接口
m_pm.AddNotifier(this);
// 窗口初始化完毕
InitWindow();//子类继承时调用
return 0;
}
请读者先仔细阅读以上源码及源码注释,第一步是修改当前绘制窗口的属性,然后获取绘制窗口所需资源路径,根据资源类型进行必要初始化,再根据xml文件构建子控件树,然后将构建的树与CPaintManagerUI对象联系起来,最好将窗口对象注册进CPaintManagerUI对象中消息处理列表中。最后调用实现窗口的初始化函数。 从以上代码可知,在WindowImplBase实现中,由于将许多核心部分放在CPaintManagerUI成员内,所以又将本身的行为再次注册到CPaintManagerUI中,当然这只是指针的一种妙用,不会带来额外的赋值负担。这其中有几个比较关键的内部函数和对象,如CDialogBuilder对象及它的Create函数,CPaintManagerUI对象的AttachDialog函数,将放在后续小节,重点讲解。
2.作者答疑如有疑问,请留言。