• CDialogBuilder 类


    说明:我这里去除了压缩文件跟资源文件只考虑_UNICODE宏

    1、首先是Create(xml)文件

    刚传进来的时候进行判断该字符串是否以'<'开头,如果是的话就会默认是xml文件的内容否则则默认是xml文件。所以咱们在给xml文件取名字的时候记得不能以尖括号开头。

    a. 当是xml文件的时候:则会调用对应的loadfromfile->loadfrommem:判断该文件的格式是utf8(有无bom)、asci或者是unicode,然后将内容拷贝到LPTSTR m_pstrXML;  然后再调用_Parse()

    b.如果是xml文件内容时直接调用_Parse()

    2、调用CControlUI* CDialogBuilder::Create(IDialogBuilderCallback* pCallback, CPaintManagerUI* pManager, CControlUI* pParent)函数

    先将全局的font、image、default、等添加到默认的属性列表。

    再将Window的属性列表添加到默认的CPaintMangerUI类中的default 字体,颜色等

    最后再调用_Parse(&root, pParent, pManager);即函数

    CControlUI* CDialogBuilder::_Parse(CMarkupNode* pRoot, CControlUI* pParent, CPaintManagerUI* pManager)

    3、关于_Parse三个参数的函数

    先根据名字来进行解析该创建哪个控件,如果没找到则进行对应的用户自定义的类型。最后如果是在不行则调用

                if( pControl == NULL && m_pCallback != NULL ) {
                    pControl = m_pCallback->CreateControl(pstrClass);
                }
    View Code

    这里的IDialogBuilderCallback* m_pCallback;是在create的时候传进来的接口,里面有对应的createcontrol函数,我们要自己创建对应的子类来实现基类的接口。

    比如duilib官方的demo

    class ComputerExamineUI : public CContainerUI
    {
    public:
        ComputerExamineUI()
        {
            CDialogBuilder builder;
            CContainerUI* pComputerExamine = static_cast<CContainerUI*>(builder.Create(_T("ComputerExamine.xml"), (UINT)0));
            if( pComputerExamine ) {
                this->Add(pComputerExamine);
            }
            else {
                this->RemoveAll();
                return;
            }
        }
    };
    
    class CDialogBuilderCallbackEx : public IDialogBuilderCallback
    {
    public:
        CControlUI* CreateControl(LPCTSTR pstrClass) 
        {
            if( _tcscmp(pstrClass, _T("ComputerExamine")) == 0 ) return new ComputerExamineUI;
            return NULL;
        }
    };
    View Code

    对应的xml:<ComputerExamine />

    完事之后

    第一步:添加完成之后如果该classname有孩子则递归调用_Parse

    第二步:如果有父节点则: pContainer = static_cast<IContainerUI*>(pParent->GetInterface(_T("IContainer")));到这里读者可能会疑惑为什么每个容器控件都有自身的InterfaceName那该如何进行识别?

    这里以CHorizontalLayout为例

    LPVOID CHorizontalLayoutUI::GetInterface(LPCTSTR pstrName)
        {
            if( _tcscmp(pstrName, DUI_CTR_HORIZONTALLAYOUT) == 0 ) return static_cast<CHorizontalLayoutUI*>(this);
            return CContainerUI::GetInterface(pstrName);
        }
    View Code

    看了这里应该知道了是如何获取到GetInterface的指针了,先在本身查找,如果找不到则向父节点查找。既然本身是容器那肯定会继承CContainerUI,即到了ContainerUI的时候就会正确返回了。

        LPVOID CContainerUI::GetInterface(LPCTSTR pstrName)
        {
            if( _tcscmp(pstrName, _T("IContainer")) == 0 ) return static_cast<IContainerUI*>(this);
            else if( _tcscmp(pstrName, DUI_CTR_CONTAINER) == 0 ) return static_cast<CContainerUI*>(this);
            return CControlUI::GetInterface(pstrName);
        }
    View Code

    第三步:将默认的属性设置到control中,最后将用户设置的属性列表设置到control中。这样子的话如果用户重新定义了属性,则会覆盖对应的默认属性。

    这里有一个pControl->SetManger(pManager, null, false); 其实这里是为了在SetAttribute属性的时候调用。

    比如:

    void CControlUI::SetVirtualWnd(LPCTSTR pstrValue)
    {
        m_sVirtualWnd = pstrValue;
        m_pManager->UsedVirtualWnd(true);
    }
    View Code

    它这里连判断pManager是否为空的都没有。所以需要调用该函数。然后在后面则进行

    if( pManager ) {
    pControl->SetManager(NULL, NULL, false);
    }

    最后说一下关于CMarkUp 跟 CMarkupNode类

    首先我们知道CMarkUp是开源的一个xml解析类,然后该类有一个XMLELEMENT* m_pElements 属性,存储了每个element的相关信息,很有疑问,为什么存储的数据是ULONG iData 跟 ULONG iStart,却不是对应的字符串,这里很容易可以找到的是:

    LPCTSTR CMarkupNode::GetName() const
    {
        if( m_pOwner == NULL ) return NULL;
        return m_pOwner->m_pstrXML + m_pOwner->m_pElements[m_iPos].iStart;
    }
    
    LPCTSTR CMarkupNode::GetValue() const
    {
        if( m_pOwner == NULL ) return NULL;
        return m_pOwner->m_pstrXML + m_pOwner->m_pElements[m_iPos].iData;
    }
    View Code

    直接返回对应的字符串!我们知道这个m_pstrXML是在刚才讲的createmem的函数中进行new的,并将文件里面的内容复制到该属性中。但是又有疑问了,那这个字符串你怎么知道有多长了,那这里就得看里面的解析函数了,在_Parse系列的函数中,当解析到了一个名字之后会在最后一个位置设置''作为字符串的结束。

    然后该XMLELEMENT存储的方式是以邻接表的方式进行存储的。

    <Button name="cxiaoln">

      datas

    </Button>

    这里的<Button name="cxiaoln">就是istart   datas就是对应的iData  当然了,这里我只是进行简单的说明,它istart进行了'0'的分割。成各个name跟对应的值。然后对应的具体属性列表则放在CMarkupNode的_MapAttributes进行相应的解析。

    CMarkupNode类进行解析对应CMarkup的属性,并将每个element的的name跟value存放在XMLATTRIBUTE m_aAttributes[MAX_XML_ATTRIBUTES]; 

  • 相关阅读:
    配置错误定义了重复的“system.web.extensions/scripting/scriptResourceHandler” 解决办法
    js 获取cookie
    jQuery+Ajax+PHP 制作简单的异步数据传输(测试用户名是否可用)
    既之前的基础,先写个简单的PHP 与数据库 的数据交流
    Web 后端--PHP 与数据库的交互
    MySQL 忘记密码怎么办?
    MySQL 继续-- Win7 安装及后续工作
    数据库初识--从MySQL 出发
    在PHP中使用MySQL Mysqli操作数据库 ,以及类操作方法
    电脑使用--快捷键等
  • 原文地址:https://www.cnblogs.com/cxiaoln/p/4401052.html
Copyright © 2020-2023  润新知