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 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

时间: 2024-10-04 09:47:00

Duilib 学习源码系列1-创建控件的相关文章

UiAutomator源码分析之获取控件信息

根据上一篇文章<UiAutomator源码分析之注入事件>开始时提到的计划,这一篇文章我们要分析的是第二点: 如何获取控件信息 我们在测试脚本中初始化一个UiObject的时候通常是像以下这个样子: UiObject appsTab = new UiObject(new UiSelector().text("Apps")); appsTab.click() 那么这个过程发生了什么呢?这就是我们接下来要说的事情了. 1. 获取控件信息顺序图 这里依然是一个手画的不规范的顺序图

Robotium源码解读-native/webview控件的获取和操作

之前基本上没接触过移动端的UITest测试,之前因为一些需求临时赶鸭子上架采用了UIAutomator,但是后来发现webview没办法识别,在预研过程中,发现Robotium跟Appium这两个神器.由于Robotium提供了webview的解析方式,遂决定研究一下. 一.环境准备以及初始化 用来说明的用例采用的是Robotium官网的一个tutorial用例-Notepad @RunWith(AndroidJUnit4.class) public class NotePadTest { pr

JGUI源码:实现日期控件显示(17)

本文实现一个日期控件显示,日期控件看起来很复杂,其实原理很简单,为了使程序逻辑看起来简单,切换日期,选择日期等事件处理部分未实现,读者可以自己尝试实现. 1.日期控件分为三个区域:顶部的显示当前日期和选择按钮区域:中间的本月日期显示列表,固定7*6=42个单元格: 底部确定.取消.当前日期选择功能. 2.思路主要是:计算出应该显示的单元格内容,然后替换body区域即可. 代码如下 <style> .jgui-datetimepicker { padding: 10px; } .jgui-dat

Duilib学习 源码下载,编译

参考:http://www.cnblogs.com/Alberl/p/3342030.html Duilib是一个windows下免费开源的directui界面库 基于众所周知的原因, 仓库现已迁移至Gitbub https://github.com/duilib/duilib 配置VS: 在VS的菜单里,选择[工具]-[选项]-[项目和解决方案]-[VC++目录], 在[包含文件]中添加目录,其路径为[Duilib]的路径, 在[库文件]中添加目录,其路径为[Lib]的路径 其中[bin]目录

日积月累系列之分页控件(js源码)

最近开发了一款分页控件,分享给大家. 主要功能和界面介绍 cform分页控件支持服务端分页.客户端分页.数据过滤.数据排序等功能. 源码介绍 cform-pager分页控件主要由三部分组成:css.scripts以及index.html,css主要是用于控制分页和列表的样式:scripts主要是负责分页数据抓取.分页控件.本地缓存.数据过滤.数据排序等功能:index.html则涉及了分页数据模板.分页容器以及相应的过滤.排序按钮. scripts介绍 scripts目录下面包含了cform-m

duilib之源码分析

http://blog.csdn.net/wogel/article/details/9631781 duilib之源码分析 <duilib之源码分析> 1 stdAfx.h * lengthof(x) 计算数组长度宏 * MAX  两值最大 * MIN  两值最小 * CLAMP(x,a,b) x在a,b之间则取x否则取最小 2 UIBase * UI_WNDSTYLE_ 窗口风格属性 * UI_CLASSSTYLE_ 窗口类属性 * TRACE(LPCTSTR pstrFormat, ..

Spark源码系列(一)spark-submit提交作业过程

前言 折腾了很久,终于开始学习Spark的源码了,第一篇我打算讲一下Spark作业的提交过程.有不明白Spark的原理的话,有另外一位大牛已经写了一个系列的Spark的源码分析了,大家可以去参考他的,他的过程图画得非常好,他写过的我可能就不写了,实在没办法比人家写得更好. 下面给出他的地址: http://www.cnblogs.com/hseagle/p/3664933.html,屌丝们,赶紧去膜拜大神吧. 这个是Spark的App运行图,它通过一个Driver来和集群通信,集群负责作业的分配

hbase源码系列(十一)Put、Delete在服务端是如何处理?

在讲完之后HFile和HLog之后,今天我想分享是Put在Region Server经历些了什么?相信前面看了<HTable探秘>的朋友都会有印象,没看过的建议回去先看看,Put是通过MultiServerCallable来提交的多个Put,好,我们就先去这个类吧,在call方法里面,我们找到了这句. responseProto = getStub().multi(controller, requestProto); 它调用了Region Server的multi方法.好,我们立即杀到HReg

hbase源码系列(七)Snapshot的过程

在看这一章之前,建议大家先去看一下snapshot的使用.可能有人会有疑问为什么要做Snapshot,hdfs不是自带了3个备份吗,这是个很大的误区,要知道hdfs的3个备份是用于防止网络传输中的失败或者别的异常情况导致数据块丢失或者不正确,它不能避免人为的删除数据导致的后果.它就想是给数据库做备份,尤其是做删除动作之前,不管是hbase还是hdfs,请经常做Snapshot,否则哪天手贱了... 直接进入主题吧,上代码. public void takeSnapshot(SnapshotDes