好了,昨天研究出了为什么加载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 attributes 114 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 factory 186 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 _DEBUG 220 221 ASSERT(pControl); 222 223 #endif // _DEBUG 224 225 if( pControl == NULL ) 226 227 { 228 229 #ifdef _DEBUG 230 231 DUITRACE(_T("未知控件:%s"),pstrClass); 232 233 #else 234 235 continue; 236 237 #endif 238 239 } 240 241 242 243 // Add children 244 245 if( node.HasChildren() ) {//是否有子节点,突然想到第一篇的控件数组中,有标记记录是否有子节点的. 246 247 _Parse(&node, pControl, pManager);//遍历子节点控件 248 249 } 250 251 // Attach to parent 252 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 else 264 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 attributes 286 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 attributes 302 303 if( node.HasAttributes() ) {//添加控件属性 304 305 TCHAR szValue[500] = { 0 }; 306 307 SIZE_T cchLen = lengthof(szValue) - 1; 308 309 // Set ordinary attributes 310 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 item 330 331 if( pReturn == NULL ) pReturn = pControl;//返回子控件队列中的第一个元素.所有<window XXXX>的节点下只能有一个子控件,多余的就被无视了 332 333 } 334 335 return pReturn; 336 337 }
好快~ 控件的创建就讲完了 有事有啥不妥的欢迎指正 谢谢了
Duilib 学习源码系列1-创建控件,布布扣,bubuko.com