zoukankan      html  css  js  c++  java
  • Duilib 源码分析(三)界面解析

    例子

    CPaintManagerUI m_PaintManager;
    CDialogBuilder builder;
    CControlUI* pRoot;
    pRoot = builder.Create(_T("duilib.xml"), (UINT)0, NULL, &m_PaintMana);
    m_PaintManager.AttachDialog(pRoot);
    

    CDialogBuilder头文件

    // 创建界面的回调函数
    class IDialogBuilderCallback
    {
    public:
        // 自定义控件
        virtual CControlUI* CreateControl(LPCTSTR pstrClass) = 0;
    };
    
    class DUILIB_API CDialogBuilder
    {
    public:
        CDialogBuilder();
        // 加载xml界面
        CControlUI* Create(STRINGorID xml, LPCTSTR type = NULL, IDialogBuilderCallback* pCallback = NULL,
            CPaintManagerUI* pManager = NULL, CControlUI* pParent = NULL);
    
        // 根据xml界面生成界面信息
        CControlUI* Create(IDialogBuilderCallback* pCallback = NULL, CPaintManagerUI* pManager = NULL,
            CControlUI* pParent = NULL);
    
        // 获取xml解析器
        CMarkup* GetMarkup();
        void GetLastErrorMessage(LPTSTR pstrMessage, SIZE_T cchMax) const;
        void GetLastErrorLocation(LPTSTR pstrSource, SIZE_T cchMax) const;
    private:
    
        // 解析界面信息,生成界面节点树,并且填充属性
        CControlUI* _Parse(CMarkupNode* parent, CControlUI* pParent = NULL, CPaintManagerUI* pManager = NULL);
    
        // xml解析器,用以读取并解析xml配置文件;
        CMarkup m_xml;
    
        // 创建界面的回调,支持定义控件的接口
        IDialogBuilderCallback* m_pCallback;
    
        // 资源类型,指定要加载什么资源
        LPCTSTR m_pstrtype;
    }
    

    CDialogBuilder源文件

    CControlUI* CDialogBuilder::Create(STRINGorID xml, LPCTSTR type, IDialogBuilderCallback* pCallback, CPaintManagerUI* pManager, CControlUI* pParent)
    {
        // 1、从字符串加载xml
        m_xml.Load(xml.m_lpstr);
        
        // 2、从文件加载xml
        m_xml.LoadFromFile(xml.m_lpstr);
        
        // 3、从资源加载xml
        HGLOBAL hGlobal = ::LoadResource(CPaintManagerUI::GetResourceDll(), hResource);
        m_xml.LoadFromMem((BYTE*)::LockResource(hGlobal), ::SizeofResource(CPaintManagerUI::GetResourceDll(), hResource);
        
      return Create(pCallback, pManager, pParent);
    }
    
    CControlUI* CDialogBuilder::Create(IDialogBuilderCallback* pCallback, CPaintManagerUI* pManager, CControlUI* pParent)
    {
        // 界面根节点
        CMarkupNode root = m_xml.GetRoot();
        
        // 遍历界面节点,获得常规属性
        for( CMarkupNode node = root.GetChild() ; node.IsValid(); node = node.GetSibling() ) 
        {
             if( _tcsicmp(pstrClass, _T("Image")) == 0 )
             else if( _tcsicmp(pstrClass, _T("Font")) == 0 )
             else if( _tcsicmp(pstrClass, _T("Default")) == 0 ) 
             else if( _tcsicmp(pstrClass, _T("MultiLanguage")) == 0 )  
        }
        
        // 最后获取属性的默认值
        if( _tcsicmp(pstrClass, _T("Window")) == 0 ) ...
        
        // 解析节点
        return _Parse(&root, pParent, pManager);
    }
    
    CControlUI* CDialogBuilder::_Parse(CMarkupNode* pRoot, CControlUI* pParent, CPaintManagerUI* pManager)
    {
        // 遍历所有节点
        for( CMarkupNode node = pRoot->GetChild() ; node.IsValid(); node = node.GetSibling() ) 
        {
            // 过滤已处理的常规属性
            if( _tcsicmp(pstrClass, _T("Image")) == 0 
                || _tcsicmp(pstrClass, _T("Font")) == 0 
                || _tcsicmp(pstrClass, _T("Default")) == 0 
    			|| _tcsicmp(pstrClass, _T("MultiLanguage")) == 0 ) 
                continue;
                
            // include 表示引入另一个xml
            if( _tcsicmp(pstrClass, _T("Include")) == 0 ) 
            {
                CDialogBuilder builder;
                CControlUI* pControl = NULL;
                pControl = builder.Create(m_pCallback, pManager, pParent);
            }
            // 处理 树节点
            else if( _tcsicmp(pstrClass, _T("TreeNode")) == 0 ) 
            {
                CTreeNodeUI* pParentNode	= static_cast<CTreeNodeUI*>(pParent->GetInterface(_T("TreeNode")));
    			CTreeNodeUI* pNode			= new CTreeNodeUI();
                pParentNode->Add(pNode)
            }
            // 处理 控件
            else
            {
                if( _tcsicmp(pstrClass, DUI_CTR_EDIT) == 0 )
                    pControl = new CEditUI;
                else if( _tcsicmp(pstrClass, DUI_CTR_LIST) == 0 )
                    pControl = new CListUI;
                ...
            }
            
            // 不是标准控件,则在插件中生成节点
            if( pControl == NULL ) 
            {
                CDuiPtrArray* pPlugins = CPaintManagerUI::GetPlugins();
                for( int i = 0; i < pPlugins->GetSize(); ++i ) 
                {
                    lpCreateControl = (LPCREATECONTROL)pPlugins->GetAt(i);
                    pControl = lpCreateControl(pstrClass);
                }
            }
            // 插件里面也没有,就在回调中生成节点,自定义控件
            if( pControl == NULL && m_pCallback != NULL ) 
            {
                pControl = m_pCallback->CreateControl(pstrClass);
            }
        }
        
        // 解析子节点
        if( node.HasChildren() ) {
            _Parse(&node, pControl, pManager);
        }
        // 先设置默认属性
        pControl->SetAttributeList(pDefaultAttributes);
        
        // 再设置节点属性
        pControl->SetAttribute(node.GetAttributeName(i), node.GetAttributeValue(i));
    }
    

    插件

    CDuiPtrArray* CPaintManagerUI::GetPlugins()
    {
        return &m_aPlugins;
    }
    
    bool CPaintManagerUI::LoadPlugin(LPCTSTR pstrModuleName)
    {
        ASSERT( !::IsBadStringPtr(pstrModuleName,-1) || pstrModuleName == NULL );
        if( pstrModuleName == NULL ) return false;
        HMODULE hModule = ::LoadLibrary(pstrModuleName);
        if( hModule != NULL ) {
            LPCREATECONTROL lpCreateControl = (LPCREATECONTROL)::GetProcAddress(hModule, "CreateControl");
            if( lpCreateControl != NULL ) {
                if( m_aPlugins.Find(lpCreateControl) >= 0 ) return true;
                m_aPlugins.Add(lpCreateControl);
                return true;
            }
        }
        return false;
    }
    
    Duilib通过LoadLibrary加载插件dll,
    在插件dll中,只需要实现一个接口CreateControl,如
    extern"C" __declspec(dllexport) CControlUI* CreateControl(LPCTSTR pstrType)
    {
        if( _tcscmp(pstrType,_T("ButtonEx")) == 0 ) return new CButtonExUI;
        return NULL;
    }
    在使用程序中,需要在WinMain函数把插件dll使用CPaintManagerUI::LoadPlugin加载进来,然后就可以和内置控件一样使用了。
    

    自定义控件

    // MenuUI
    const TCHAR* const kMenuUIClassName = _T("MenuUI");
    const TCHAR* const kMenuUIInterfaceName = _T("Menu");
    class CMenuBuilderCallback: public IDialogBuilderCallback
    {
    	CControlUI* CreateControl(LPCTSTR pstrClass)
    	{
    		if (_tcsicmp(pstrClass, kMenuUIInterfaceName) == 0)
    		{
    			return new CMenuUI();
    		}
    		else if (_tcsicmp(pstrClass, kMenuElementUIInterfaceName) == 0)
    		{
    			return new CMenuElementUI();
    		}
    		return NULL;
    	}
    };
    

      
    小结
      Duilib加载界面信息的三个来源:字符串,文件,内存。Duilib控件的三个来源:标准控件、插件、自定义控件。

      
    Duilib技术交流群:799142530
    源码地址:https://github.com/KongKong20/DuilibTutor

  • 相关阅读:
    [洛谷P2184]贪婪大陆
    [BJOI2006]狼抓兔子
    [JSOI2007]重要的城市(x)
    [NOIP2011提高组]Mayan游戏
    gitee 使用
    部分激光打印机清零方法
    django2.0内置分页
    django上下文处理器
    jquery键盘事件
    类视图装饰器
  • 原文地址:https://www.cnblogs.com/wwgk/p/14344655.html
Copyright © 2011-2022 走看看