首页 > 代码库 > Duilib 学习源码系列1-创建控件

Duilib 学习源码系列1-创建控件

    好了,昨天研究出了为什么加载xml结束以后我在自己新建一个控件位置不能调整,原来要先add才能调属性。

    本来这个是昨天的任务,虽然这块内容是前天就看完的,权当边写边复习吧。

    上一篇提到

    <VerticalLayout name="window" bkcolor="#FFFFFFFF" bkcolor2="#FFAAAAA0" bkcolor3="#00000000"> 代表了一个控件字符串;

    上次忘记说了 及时经过那个parser函数处理以后 变成了:

    0VerticalLayout0name0"window"0bkcolor0"#FFFFFFFF"0bkcolor20"#FFAAAAA0"0bkcolor30"#00000000"0

    0代表了原先这个位置的ascii码已经变成了0,也就是字符串结尾标记。

    这样做有啥好处?

    比如你知道这个控件字符串的起始位置,那么假设这个控件字符串是一个LPCTSTR类型的指针LpStr

    那么 CString ControlName = LpStr;此时,ControlName的值就为VerticalLayout;

    那么之后就可以获得属性的偏移量,为LpStr + ControlName.Getlenth()*sizeof(WCHAR);

    之后我们就可以依照类似的方法建立一张属性的表,只需要记录下属性名称的偏移量以及属性值的偏移量.之后就可以获得你要获得属性值了。

    (PS:duilib 内部不会像我这么sb的来操作,不过基本道理差不多。);

    每一个控件都存在一个叫做CMarkupNode的类中来维护的。

    好了下面说说创建控件了。。

    CControlUI* CDialogBuilder::Create(IDialogBuilderCallback* pCallback, CPaintManagerUI* pManager, CControlUI* pParent)先是调用这个函数来把windows窗口的设置弄好(大小啊,字体啊之类的);

之后就是调用CControlUI* CDialogBuilder::_Parse(CMarkupNode* pRoot, CControlUI* pParent, CPaintManagerUI* pManager)来创建(贴代码!)

  1 CControlUI* CDialogBuilder::_Parse(CMarkupNode* pRoot, CControlUI* pParent, CPaintManagerUI* pManager)  2   3 {  4   5     IContainerUI* pContainer = NULL;  6   7     CControlUI* pReturn = NULL;  8   9     for( CMarkupNode node = pRoot->GetChild() ; node.IsValid(); node = node.GetSibling() ) {//检索子控件队列(第一次进入该函数 proot指向的节点必然是<windows XXXXXXX >这个节点.因为控件队列的最顶端且最前面的就是他) 10  11         LPCTSTR pstrClass = node.GetName(); 12  13         if( _tcscmp(pstrClass, _T("Image")) == 0 || _tcscmp(pstrClass, _T("Font")) == 0  14  15             || _tcscmp(pstrClass, _T("Default")) == 0 ) continue; 16  17   18  19         CControlUI* pControl = NULL; 20  21         if( _tcscmp(pstrClass, _T("Include")) == 0 ) { 22  23             if( !node.HasAttributes() ) continue; 24  25             int count = 1; 26  27             LPTSTR pstr = NULL; 28  29             TCHAR szValue[500] = { 0 }; 30  31             SIZE_T cchLen = lengthof(szValue) - 1; 32  33             if ( node.GetAttributeValue(_T("count"), szValue, cchLen) ) 34  35                 count = _tcstol(szValue, &pstr, 10); 36  37             cchLen = lengthof(szValue) - 1; 38  39             if ( !node.GetAttributeValue(_T("source"), szValue, cchLen) ) continue; 40  41             for ( int i = 0; i < count; i++ ) { 42  43                 CDialogBuilder builder; 44  45                 if( m_pstrtype != NULL ) { // 使用资源dll,从资源中读取 46  47                     WORD id = (WORD)_tcstol(szValue, &pstr, 10);  48  49                     pControl = builder.Create((UINT)id, m_pstrtype, m_pCallback, pManager, pParent); 50  51                 } 52  53                 else { 54  55                     pControl = builder.Create((LPCTSTR)szValue, (UINT)0, m_pCallback, pManager, pParent); 56  57                 } 58  59             } 60  61             continue; 62  63         } 64  65         //树控件XML解析 66  67         else if( _tcscmp(pstrClass, _T("TreeNode")) == 0 ) { 68  69             CTreeNodeUI* pParentNode    = static_cast<CTreeNodeUI*>(pParent->GetInterface(_T("TreeNode"))); 70  71             CTreeNodeUI* pNode            = new CTreeNodeUI(); 72  73             if(pParentNode){ 74  75                 if(!pParentNode->Add(pNode)){ 76  77                     delete pNode; 78  79                     continue; 80  81                 } 82  83             } 84  85   86  87             // 若有控件默认配置先初始化默认属性 88  89             if( pManager ) { 90  91                 pNode->SetManager(pManager, NULL, false); 92  93                 LPCTSTR pDefaultAttributes = pManager->GetDefaultAttributeList(pstrClass); 94  95                 if( pDefaultAttributes ) { 96  97                     pNode->ApplyAttributeList(pDefaultAttributes); 98  99                 }100 101             }102 103  104 105             // 解析所有属性并覆盖默认属性106 107             if( node.HasAttributes() ) {108 109                 TCHAR szValue[500] = { 0 };110 111                 SIZE_T cchLen = lengthof(szValue) - 1;112 113                 // Set ordinary attributes114 115                 int nAttributes = node.GetAttributeCount();116 117                 for( int i = 0; i < nAttributes; i++ ) {118 119                     pNode->SetAttribute(node.GetAttributeName(i), node.GetAttributeValue(i));120 121                 }122 123             }124 125  126 127             //检索子节点及附加控件128 129             if(node.HasChildren()){130 131                 CControlUI* pSubControl = _Parse(&node,pNode,pManager);132 133                 if(pSubControl && _tcscmp(pSubControl->GetClass(),_T("TreeNodeUI")) != 0)134 135                 {136 137                     //                     pSubControl->SetFixedWidth(30);138 139                     //                     CHorizontalLayoutUI* pHorz = pNode->GetTreeNodeHoriznotal();140 141                     //                     pHorz->Add(new CEditUI());142 143                     //                     continue;144 145                 }146 147             }148 149  150 151             if(!pParentNode){152 153                 CTreeViewUI* pTreeView = static_cast<CTreeViewUI*>(pParent->GetInterface(_T("TreeView")));154 155                 ASSERT(pTreeView);156 157                 if( pTreeView == NULL ) return NULL;158 159                 if( !pTreeView->Add(pNode) ) {160 161                     delete pNode;162 163                     continue;164 165                 }166 167             }168 169             continue;170 171         }172 173 //这里开始的上面那部分我没怎么看懂- - 毕竟还没有写过duilib的程序有些属性完全不了解- - 我感觉好像就是对一些依赖的东西做些初始化174 175         else {176 177             SIZE_T cchLen = _tcslen(pstrClass);178 179             switch( cchLen ) {//new 相应的控件180 181                …(此处篇幅太大,以删除,总而言之就是根据控件类型来new对应的类)182 183             }184 185             // User-supplied control factory186 187             if( pControl == NULL ) {188 189                 CStdPtrArray* pPlugins = CPaintManagerUI::GetPlugins();190 191                 LPCREATECONTROL lpCreateControl = NULL;192 193                 for( int i = 0; i < pPlugins->GetSize(); ++i ) {194 195                     lpCreateControl = (LPCREATECONTROL)pPlugins->GetAt(i);196 197                     if( lpCreateControl != NULL ) {198 199                         pControl = lpCreateControl(pstrClass);200 201                         if( pControl != NULL ) break;202 203                     }204 205                 }206 207             }208 209             if( pControl == NULL && m_pCallback != NULL ) {210 211                 pControl = m_pCallback->CreateControl(pstrClass);212 213             }214 215         }216 217  218 219 #ifndef _DEBUG220 221         ASSERT(pControl);222 223 #endif // _DEBUG224 225             if( pControl == NULL )226 227             {228 229 #ifdef _DEBUG230 231                 DUITRACE(_T("未知控件:%s"),pstrClass);232 233 #else234 235                 continue;236 237 #endif238 239             }240 241  242 243         // Add children244 245         if( node.HasChildren() ) {//是否有子节点,突然想到第一篇的控件数组中,有标记记录是否有子节点的.246 247             _Parse(&node, pControl, pManager);//遍历子节点控件248 249         }250 251         // Attach to parent252 253         // 因为某些属性和父窗口相关,比如selected,必须先Add到父窗口254 255         if( pParent != NULL ) {//加入父控件队列中256 257             CTreeNodeUI* pContainerNode = static_cast<CTreeNodeUI*>(pParent->GetInterface(_T("TreeNode")));258 259             if(pContainerNode)260 261                 pContainerNode->GetTreeNodeHoriznotal()->Add(pControl);262 263             else264 265             {266 267                 if( pContainer == NULL ) pContainer = static_cast<IContainerUI*>(pParent->GetInterface(_T("IContainer")));268 269                 ASSERT(pContainer);270 271                 if( pContainer == NULL ) return NULL;272 273                 if( !pContainer->Add(pControl) ) {//父节点将子节点加入父节点的子控件队列中.274 275                     delete pControl;276 277                     continue;278 279                 }280 281             }282 283         }284 285         // Init default attributes286 287         if( pManager ) {288 289             pControl->SetManager(pManager, NULL, false);290 291             LPCTSTR pDefaultAttributes = pManager->GetDefaultAttributeList(pstrClass);292 293             if( pDefaultAttributes ) {294 295                 pControl->ApplyAttributeList(pDefaultAttributes);296 297             }298 299         }300 301         // Process attributes302 303         if( node.HasAttributes() ) {//添加控件属性304 305             TCHAR szValue[500] = { 0 };306 307             SIZE_T cchLen = lengthof(szValue) - 1;308 309             // Set ordinary attributes310 311             int nAttributes = node.GetAttributeCount();312 313             for( int i = 0; i < nAttributes; i++ ) {314 315                 pControl->SetAttribute(node.GetAttributeName(i), node.GetAttributeValue(i));316 317         // GetAttributeXXXX这个函数就是前面所说的属性建表了,根据序号取出对应的值以及属性名称,其实内部不止根据序号,还有属性名称来取对应的值等等操作318 319             }320 321         }322 323         if( pManager ) {324 325             pControl->SetManager(NULL, NULL, false);//清空信息(虽然我也不知道为什么要这么做)不过看了下后面的代码会重新赋值的.不过子节点设置父节点为空,但是父节点依旧可以找到子节点…326 327         }328 329         // Return first item330 331         if( pReturn == NULL ) pReturn = pControl;//返回子控件队列中的第一个元素.所有<window XXXX>的节点下只能有一个子控件,多余的就被无视了332 333     }334 335     return pReturn;336 337 }

 

好快~ 控件的创建就讲完了 有事有啥不妥的欢迎指正 谢谢了