您当前的位置: 首页 >  ui

插件开发

暂无认证

  • 1浏览

    0关注

    492博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

第一章 第六小节Duilib的WindowImplBase基类OnCreate函数-创建流程

插件开发 发布时间:2022-03-25 07:37:03 ,浏览量:1

文章目录
    • 1.OnCreate函数
    • 2.作者答疑

1.OnCreate函数

  有了前面对消息传递的详细讲解,接下来是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.作者答疑

  如有疑问,请留言。

关注
打赏
1665481431
查看更多评论
立即登录/注册

微信扫码登录

0.0398s