上一篇讲了窗口及消息,了解了大体的程序框架。这一篇说的是控件的创建。

duilib支持XML配置文件,即根据XML创建窗口及控件,将界面与逻辑分开,便于修改及维护。上一篇的示例中可以看到在消息WM_CREATE中有控件创建的相关代码。

 if( uMsg == WM_CREATE ) {
m_pm.Init(m_hWnd);
//根据XML创建控件
CDialogBuilder builder;
CControlUI* pRoot = builder.Create(_T("HelloWorld.xml"), (UINT), NULL, &m_pm);
ASSERT(pRoot && "Failed to parse XML");
m_pm.AttachDialog(pRoot);
m_pm.AddNotifier(this);
return ;
}

控件创建主要牵扯到类CDialogBuilder:

  • 创建控件树,返回根控件:CDialogBuilder::Create
  • 将控件树关联到CPaintManagerUI对象(由名字可猜出其功能与绘制控件有关):CPaintManagerUI::AttachDialog
  • 添加消息通知:CPaintManagerUI::AddNotifier

创建控件树:

  • 读取XML配置文件

     CControlUI* CDialogBuilder::Create(STRINGorID xml, LPCTSTR type, IDialogBuilderCallback* pCallback,
    CPaintManagerUI* pManager, CControlUI* pParent)
    {
    if( HIWORD(xml.m_lpstr) != NULL ) {
    if( *(xml.m_lpstr) == _T('<') ) {
    if( !m_xml.Load(xml.m_lpstr) ) return NULL;
    }
    else {
    if( !m_xml.LoadFromFile(xml.m_lpstr) ) return NULL;
    }
    }
    else {
    HRSRC hResource = ::FindResource(CPaintManagerUI::GetResourceDll(), xml.m_lpstr, type);
    if( hResource == NULL ) return NULL;
    HGLOBAL hGlobal = ::LoadResource(CPaintManagerUI::GetResourceDll(), hResource);
    if( hGlobal == NULL ) {
    FreeResource(hResource);
    return NULL;
    } m_pCallback = pCallback;
    if( !m_xml.LoadFromMem((BYTE*)::LockResource(hGlobal), ::SizeofResource(CPaintManagerUI::GetResourceDll(), hResource) )) return NULL;
    ::FreeResource(hResource);
    m_pstrtype = type;
    } return Create(pCallback, pManager);
    }
  • 解析Image(图片)、Font(字体)、Default(默认属性)、Windows(窗口相关)项(代码太长,省略了细节)

     CControlUI* CDialogBuilder::Create(IDialogBuilderCallback* pCallback, CPaintManagerUI* pManager, CControlUI* pParent)
    {
    m_pCallback = pCallback;//回调函数,用于创建自定义控件
    CMarkupNode root = m_xml.GetRoot();
    if( !root.IsValid() ) return NULL; if( pManager ) {
    LPCTSTR pstrClass = NULL;
    int nAttributes = ;
    LPCTSTR pstrName = NULL;
    LPCTSTR pstrValue = NULL;
    LPTSTR pstr = NULL;
    for( CMarkupNode node = root.GetChild() ; node.IsValid(); node = node.GetSibling() ) {
    pstrClass = node.GetName();
    if( _tcscmp(pstrClass, _T("Image")) == ) {//Image
    }
    else if( _tcscmp(pstrClass, _T("Font")) == ) {//Font
    }
    else if( _tcscmp(pstrClass, _T("Default")) == ) {//Default
    }
    } pstrClass = root.GetName();
    if( _tcscmp(pstrClass, _T("Window")) == ) {//Window
    }
    }
    return _Parse(&root, NULL, pManager);
    }
  • 创建控件:CDialogBuilder::_Parse
    • 可以通过include嵌套XML文件

       。。。。。。
      if( _tcscmp(pstrClass, _T("Include")) == ) {//Include
      if( !node.HasAttributes() ) continue;
      int count = ;
      LPTSTR pstr = NULL;
      TCHAR szValue[] = { };
      SIZE_T cchLen = lengthof(szValue) - ;
      if ( node.GetAttributeValue(_T("count"), szValue, cchLen) )
      count = _tcstol(szValue, &pstr, );
      cchLen = lengthof(szValue) - ;
      if ( !node.GetAttributeValue(_T("source"), szValue, cchLen) ) continue;
      for ( int i = ; i < count; i++ ) {
      CDialogBuilder builder;
      if( m_pstrtype != NULL ) { // 使用资源dll,从资源中读取
      WORD id = (WORD)_tcstol(szValue, &pstr, );
      pControl = builder.Create((UINT)id, m_pstrtype, m_pCallback, pManager, pParent);
      }
      else {
      pControl = builder.Create((LPCTSTR)szValue, (UINT), m_pCallback, pManager, pParent);
      }
      }
      continue;
      }
      。。。。。。
    • 创建控件(自定义控件调用回调函数实现)
      。。。。。。
      else {//新建控件
      SIZE_T cchLen = _tcslen(pstrClass);
      switch( cchLen ) {
      case :
      if( _tcscmp(pstrClass, _T("Edit")) == ) pControl = new CEditUI;
      else if( _tcscmp(pstrClass, _T("List")) == ) pControl = new CListUI;
      else if( _tcscmp(pstrClass, _T("Text")) == ) pControl = new CTextUI;
      break;
      case :
      if( _tcscmp(pstrClass, _T("Combo")) == ) pControl = new CComboUI;
      else if( _tcscmp(pstrClass, _T("Label")) == ) pControl = new CLabelUI;
      break;
      case :
      if( _tcscmp(pstrClass, _T("Button")) == ) pControl = new CButtonUI;
      else if( _tcscmp(pstrClass, _T("Option")) == ) pControl = new COptionUI;
      else if( _tcscmp(pstrClass, _T("Slider")) == ) pControl = new CSliderUI;
      break;
      case :
      if( _tcscmp(pstrClass, _T("Control")) == ) pControl = new CControlUI;
      else if( _tcscmp(pstrClass, _T("ActiveX")) == ) pControl = new CActiveXUI;
      break;
      case :
      if( _tcscmp(pstrClass, _T("Progress")) == ) pControl = new CProgressUI;
      else if( _tcscmp(pstrClass, _T("RichEdit")) == ) pControl = new CRichEditUI;
      break;
      case :
      if( _tcscmp(pstrClass, _T("Container")) == ) pControl = new CContainerUI;
      else if( _tcscmp(pstrClass, _T("TabLayout")) == ) pControl = new CTabLayoutUI;
      else if( _tcscmp(pstrClass, _T("ScrollBar")) == ) pControl = new CScrollBarUI;
      break;
      case :
      if( _tcscmp(pstrClass, _T("ListHeader")) == ) pControl = new CListHeaderUI;
      else if( _tcscmp(pstrClass, _T("TileLayout")) == ) pControl = new CTileLayoutUI;
      break;
      case :
      if( _tcscmp(pstrClass, _T("DialogLayout")) == ) pControl = new CDialogLayoutUI;
      break;
      case :
      if( _tcscmp(pstrClass, _T("VerticalLayout")) == ) pControl = new CVerticalLayoutUI;
      else if( _tcscmp(pstrClass, _T("ListHeaderItem")) == ) pControl = new CListHeaderItemUI;
      break;
      case :
      if( _tcscmp(pstrClass, _T("ListTextElement")) == ) pControl = new CListTextElementUI;
      break;
      case :
      if( _tcscmp(pstrClass, _T("HorizontalLayout")) == ) pControl = new CHorizontalLayoutUI;
      else if( _tcscmp(pstrClass, _T("ListLabelElement")) == ) pControl = new CListLabelElementUI;
      break;
      case :
      if( _tcscmp(pstrClass, _T("ListContainerElement")) == ) pControl = new CListContainerElementUI;
      break;
      }
      // User-supplied control factory
      if( pControl == NULL && m_pCallback != NULL ) {
      pControl = m_pCallback->CreateControl(pstrClass);
      }
      }
      。。。。。。
    • 添加子控件(解析子控件:递归调用_Parse、关联到父控件:CContainerUI::Add)
       。。。。。。
      // Add children
      if( node.HasChildren() ) {
      _Parse(&node, pControl, pManager);
      }
      // Attach to parent
      // 因为某些属性和父窗口相关,比如selected,必须先Add到父窗口
      if( pParent != NULL ) {
      if( pContainer == NULL ) pContainer = static_cast<IContainerUI*>(pParent->GetInterface(_T("IContainer")));
      ASSERT(pContainer);
      if( pContainer == NULL ) return NULL;
      if( !pContainer->Add(pControl) ) {
      delete pControl;
      continue;
      }
      }
      。。。。。。
    • 返回根控件
    •  。。。。。。
      // Return first item
      if( pReturn == NULL ) pReturn = pControl;
      。。。。。。

控件创建基本就这些,下一篇写控件消息。

DuiLib(二)——控件创建的更多相关文章

  1. SNF开发平台WinForm之三-开发-单表选择控件创建-SNF快速开发平台3.3-Spring.Net.Framework

    3.1运行效果: 3.2开发实现: 3.2.1 这个开发与第一个开发操作步骤是一致的,不同之处就是在生成完代码之后,留下如下圈红程序,其它删除. 第一个开发地址:开发-单表表格编辑管理页面 http: ...

  2. 通过WinForm控件创建的WPF控件无法输入的问题

    今天把写的一个WPF程序发布到别的机器上执行,发现一个比较奇怪的问题:在那个机器上用英文输入法无法输入数字,非要切换到中文输入法才行:但在我的机器上却是好好的. 最开始以为是输入法的问题,弄了好一阵子 ...

  3. 通过C# WinForm控件创建的WPF WIndow窗口控件无法输入的问题

    原文:通过WinForm控件创建的WPF 控件无法输入的问题 今天把写的一个WPF程序发布到别的机器上执行,发现一个比较奇怪的问题:在那个机器上用英文输入法无法输入数字,非要切换到中文输入法才行:但在 ...

  4. Duilib源码分析(二)控件构造器—CDialogBuilder

    上一节了解了大体流程,但是界面控件元素是如何被加载.解析.构建.管理.控件消息如何处理的呢?接下来我们将结合控件构造器进行分析: CDialogBuilder:控件构造器,主要用以解析xml配置文件并 ...

  5. 修复duilib CEditUI控件和CWebBrowserUI控件中按Tab键无法切换焦点的bug

    转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/41556615 在duilib中,按tab键会让焦点在Button一类的控 ...

  6. duilib List控件,横向滚动时列表项不移动或者显示错位的bug的修复

    转载请说明出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/42264673 关于这个bug的修复我之前写过一篇博客,连接为:http:/ ...

  7. duilib combo控件,当鼠标滚动时下拉列表自动关闭的bug的修复

    转载请说明出处,谢谢~~ 群里有朋友提到了使用Combo控件时,当下拉列表出现,此时鼠标滚轮滚动,下拉列表就自动消失了.我看了一下源码,这个bug的修复很简单. CComboUI控件被单击时创建CCo ...

  8. 增加duilib edit控件的提示功能和多种文字颜色

    转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/41786407 duilib的CEditUI控件内部使用了win32的原生 ...

  9. duilib List控件,横向滚动时列表项不移动或者移动错位的bug的修复

    转载请说明出处,谢谢~~ 这篇博客已经作废,只是留作记录,新的bug修复博客地址:http://blog.csdn.net/zhuhongshu/article/details/42264673 之前 ...

随机推荐

  1. Android-AnimationDrawable(三)运行的几种方式

    项目开发用到了AnimationDrawable,调用start后没有运行,很纳闷.google搜了下.记录一下. 这个AnimationDrawable.start不能直接写在onClick,onS ...

  2. 底部菜单栏(二) TabHost & RadioGroup 实现

    需求:使用TabHost & RadioGroup实现底部菜单栏: 效果图: 实现分析: 1.目录结构: 代码实现: 1. activity_main.xml <?xml version ...

  3. OLAP、OLTP的介绍和比较 via csdn

    OLAP.OLTP的介绍和比较 数据处理大致可以分成两大类: OLTP(On-Line Transaction Processing)联机事务处理 也称为面向交易的处理系统,其基本特征是顾客的原始数据 ...

  4. IOS 五星评分控件

    程序中需要打分的功能,在网上找了几个,都不是很满意.下面是实现出的效果.可以点击,可以拖动. 使用方法:初始化控件. TQStarRatingView *starRatingView = [[TQSt ...

  5. hdu 3342 Legal or Not(拓扑排序) HDOJ Monthly Contest – 2010.03.06

    一道极其水的拓扑排序……但是我还是要把它发出来,原因很简单,连错12次…… 题意也很裸,前面的废话不用看,直接看输入 输入n, m表示从0到n-1共n个人,有m组关系 截下来m组,每组输入a, b表示 ...

  6. Apache OFBiz 学习笔记 之 服务引擎 一

    概述     服务定义为一段独立的逻辑顺序,当多个服务组合一起时可完成不同类型的业务需求     服务有很多类型,WorkFlow.Rules.Java.SOAP.BeanShell等.java类型的 ...

  7. ASP.NET中常用的字符串分割函数

    asp.net字符串分割函数用法 先来看个简单的实例 但是其数组长度却是25,而不是3.下面这种方法是先将“[111cn.net]”替换成一个特殊字符,比如$,在根据这个字符执行Split 例如下面我 ...

  8. 【九度OJ】题目1009-二叉搜索树

    题目 思路 构建二叉搜索树,并保存先序遍历和中序遍历的序列在samplePreOrder,sampleInOrder 每遇到一个新的序列,构建一棵二叉搜索树,保存先序遍历和中序遍历的序列testPre ...

  9. Python相关书籍推荐

    Python基础教程(第2版 修订版) 作      者 [挪] Magnus Lie Hetland 著:司维,曾军崴,谭颖华 译 出 版 社 人民邮电出版社 出版时间 2014-06-01 版   ...

  10. CSS框模型(框模型概述、内边距、边框、外边距、外边距合并)

    CSS 框模型概述 CSS 框模型 (Box Model) 规定了元素框处理元素内容.内边距.边框 和 外边距 的方式. 元素框的最内部分是实际的内容,直接包围内容的是内边距.内边距呈现了元素的背景. ...