您的位置:首页 > 产品设计 > UI/UE

DuiLib(二)——控件创建

2013-12-03 15:28 387 查看
上一篇讲了窗口及消息,了解了大体的程序框架。这一篇说的是控件的创建。

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)0, NULL, &m_pm);
ASSERT(pRoot && "Failed to parse XML");
m_pm.AttachDialog(pRoot);
m_pm.AddNotifier(this);
return 0;
}


控件创建主要牵扯到类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 = 0;
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")) == 0 ) {//Image
}
else if( _tcscmp(pstrClass, _T("Font")) == 0 ) {//Font
}
else if( _tcscmp(pstrClass, _T("Default")) == 0 ) {//Default
}
}

pstrClass = root.GetName();
if( _tcscmp(pstrClass, _T("Window")) == 0 ) {//Window
}
}
return _Parse(&root, NULL, pManager);
}


创建控件:CDialogBuilder::_Parse

可以通过include嵌套XML文件

。。。。。。
if( _tcscmp(pstrClass, _T("Include")) == 0 ) {//Include
if( !node.HasAttributes() ) continue;
int count = 1;
LPTSTR pstr = NULL;
TCHAR szValue[500] = { 0 };
SIZE_T cchLen = lengthof(szValue) - 1;
if ( node.GetAttributeValue(_T("count"), szValue, cchLen) )
count = _tcstol(szValue, &pstr, 10);
cchLen = lengthof(szValue) - 1;
if ( !node.GetAttributeValue(_T("source"), szValue, cchLen) ) continue;
for ( int i = 0; i < count; i++ ) {
CDialogBuilder builder;
if( m_pstrtype != NULL ) { // 使用资源dll,从资源中读取
WORD id = (WORD)_tcstol(szValue, &pstr, 10);
pControl = builder.Create((UINT)id, m_pstrtype, m_pCallback, pManager, pParent);
}
else {
pControl = builder.Create((LPCTSTR)szValue, (UINT)0, m_pCallback, pManager, pParent);
}
}
continue;
}
。。。。。。


创建控件(自定义控件调用回调函数实现)

。。。。。。
else {//新建控件
SIZE_T cchLen = _tcslen(pstrClass);
switch( cchLen ) {
case 4:
if( _tcscmp(pstrClass, _T("Edit")) == 0 )                   pControl = new CEditUI;
else if( _tcscmp(pstrClass, _T("List")) == 0 )              pControl = new CListUI;
else if( _tcscmp(pstrClass, _T("Text")) == 0 )              pControl = new CTextUI;
break;
case 5:
if( _tcscmp(pstrClass, _T("Combo")) == 0 )                  pControl = new CComboUI;
else if( _tcscmp(pstrClass, _T("Label")) == 0 )             pControl = new CLabelUI;
break;
case 6:
if( _tcscmp(pstrClass, _T("Button")) == 0 )                 pControl = new CButtonUI;
else if( _tcscmp(pstrClass, _T("Option")) == 0 )            pControl = new COptionUI;
else if( _tcscmp(pstrClass, _T("Slider")) == 0 )            pControl = new CSliderUI;
break;
case 7:
if( _tcscmp(pstrClass, _T("Control")) == 0 )                pControl = new CControlUI;
else if( _tcscmp(pstrClass, _T("ActiveX")) == 0 )           pControl = new CActiveXUI;
break;
case 8:
if( _tcscmp(pstrClass, _T("Progress")) == 0 )               pControl = new CProgressUI;
else if(  _tcscmp(pstrClass, _T("RichEdit")) == 0 )         pControl = new CRichEditUI;
break;
case 9:
if( _tcscmp(pstrClass, _T("Container")) == 0 )              pControl = new CContainerUI;
else if( _tcscmp(pstrClass, _T("TabLayout")) == 0 )         pControl = new CTabLayoutUI;
else if( _tcscmp(pstrClass, _T("ScrollBar")) == 0 )         pControl = new CScrollBarUI;
break;
case 10:
if( _tcscmp(pstrClass, _T("ListHeader")) == 0 )             pControl = new CListHeaderUI;
else if( _tcscmp(pstrClass, _T("TileLayout")) == 0 )        pControl = new CTileLayoutUI;
break;
case 12:
if( _tcscmp(pstrClass, _T("DialogLayout")) == 0 )           pControl = new CDialogLayoutUI;
break;
case 14:
if( _tcscmp(pstrClass, _T("VerticalLayout")) == 0 )         pControl = new CVerticalLayoutUI;
else if( _tcscmp(pstrClass, _T("ListHeaderItem")) == 0 )    pControl = new CListHeaderItemUI;
break;
case 15:
if( _tcscmp(pstrClass, _T("ListTextElement")) == 0 )        pControl = new CListTextElementUI;
break;
case 16:
if( _tcscmp(pstrClass, _T("HorizontalLayout")) == 0 )       pControl = new CHorizontalLayoutUI;
else if( _tcscmp(pstrClass, _T("ListLabelElement")) == 0 )  pControl = new CListLabelElementUI;
break;
case 20:
if( _tcscmp(pstrClass, _T("ListContainerElement")) == 0 )   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;
。。。。。。


控件创建基本就这些,下一篇写控件消息。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: