首页 > 代码库 > 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 }
好快~ 控件的创建就讲完了 有事有啥不妥的欢迎指正 谢谢了