DuiLib(二)——控件创建
上一篇讲了窗口及消息,了解了大体的程序框架。这一篇说的是控件的创建。
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;
。。。。。。
- 可以通过include嵌套XML文件
控件创建基本就这些,下一篇写控件消息。
DuiLib(二)——控件创建的更多相关文章
- SNF开发平台WinForm之三-开发-单表选择控件创建-SNF快速开发平台3.3-Spring.Net.Framework
3.1运行效果: 3.2开发实现: 3.2.1 这个开发与第一个开发操作步骤是一致的,不同之处就是在生成完代码之后,留下如下圈红程序,其它删除. 第一个开发地址:开发-单表表格编辑管理页面 http: ...
- 通过WinForm控件创建的WPF控件无法输入的问题
今天把写的一个WPF程序发布到别的机器上执行,发现一个比较奇怪的问题:在那个机器上用英文输入法无法输入数字,非要切换到中文输入法才行:但在我的机器上却是好好的. 最开始以为是输入法的问题,弄了好一阵子 ...
- 通过C# WinForm控件创建的WPF WIndow窗口控件无法输入的问题
原文:通过WinForm控件创建的WPF 控件无法输入的问题 今天把写的一个WPF程序发布到别的机器上执行,发现一个比较奇怪的问题:在那个机器上用英文输入法无法输入数字,非要切换到中文输入法才行:但在 ...
- Duilib源码分析(二)控件构造器—CDialogBuilder
上一节了解了大体流程,但是界面控件元素是如何被加载.解析.构建.管理.控件消息如何处理的呢?接下来我们将结合控件构造器进行分析: CDialogBuilder:控件构造器,主要用以解析xml配置文件并 ...
- 修复duilib CEditUI控件和CWebBrowserUI控件中按Tab键无法切换焦点的bug
转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/41556615 在duilib中,按tab键会让焦点在Button一类的控 ...
- duilib List控件,横向滚动时列表项不移动或者显示错位的bug的修复
转载请说明出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/42264673 关于这个bug的修复我之前写过一篇博客,连接为:http:/ ...
- duilib combo控件,当鼠标滚动时下拉列表自动关闭的bug的修复
转载请说明出处,谢谢~~ 群里有朋友提到了使用Combo控件时,当下拉列表出现,此时鼠标滚轮滚动,下拉列表就自动消失了.我看了一下源码,这个bug的修复很简单. CComboUI控件被单击时创建CCo ...
- 增加duilib edit控件的提示功能和多种文字颜色
转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/41786407 duilib的CEditUI控件内部使用了win32的原生 ...
- duilib List控件,横向滚动时列表项不移动或者移动错位的bug的修复
转载请说明出处,谢谢~~ 这篇博客已经作废,只是留作记录,新的bug修复博客地址:http://blog.csdn.net/zhuhongshu/article/details/42264673 之前 ...
随机推荐
- 【C#学习笔记】指针使用
using System; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { ; un ...
- android和ios流媒体库推荐
1基本信息编辑 Vitamio是一款 Android 与 iOS 平台上的全能多媒体开发框架,全面支持硬件解码与 GPU 渲染.从2011年8月上线到2014年1月,Vitamio 凭借其简洁易用的 ...
- 常用UI布局
1.LinearLayout(线性布局):将布局所包含的控件在线性方向上依次排列. <1>android:orientation 指定了排列方向(垂直方向(vertical).水平方向(h ...
- webview javascript 注入方法
Android中向webview注入js代码可以通过webview.loadUrl("javascript:xxx")来实现,然后就会执行javascript后面的代码. 但是当需 ...
- MySQL auto_increment的坑
背景: Innodb引擎使用B_tree结构保存表数据,这样就需要一个唯一键表示每一行记录(比如二级索引记录引用). Innodb表定义中处理主键的逻辑是: 1.如果表定义了主键,就使用主键唯一定位一 ...
- POJ 1077 Eight
题意:经典的八数码=3= 3*3的格子,里面有1~8这8个数字,还有一个空格x,移动空格的位置,直到移到1~8按顺序排好,输出移动的序列. 解法:看到题果断写了个广搜……然后T了……百度了一下说广搜虽 ...
- Oracle EM 不能访问
zwt2001267 原文 Oracle EM 不能访问 1. cmd控制启动EM: C:\Users\Administrator>emctl start dbconsoleEnvironmen ...
- C# chart,有关如何在鼠标移动到Series上时显示节点及数据 (有待继续更新)
一.效果与思路 效果: 解决方案1 用chart的mousemove时间,实时跟踪鼠标最近的X轴的位置,然后把cursorX设置到那个位置上,让用户知道我是选的那一个X的值,同时用tooltip显示该 ...
- 大数据性能调优之HBase的RowKey设计
1 概述 HBase是一个分布式的.面向列的数据库,它和一般关系型数据库的最大区别是:HBase很适合于存储非结构化的数据,还有就是它基于列的而不是基于行的模式. 既然HBase是采用KeyValue ...
- quick-x在windows平台打包加密文件
D:\quick-cocos2d-x-2.2.1-rc\bin>compile_scripts -i ..\mygames\myth\scripts -o ..\mygames\myth\res ...