文章目录
1.CDialogBuilder对象中Parse函数
- 1.CDialogBuilder对象中Parse函数
- 2.作者答疑
接着上一部分讲解,已经获取了文件中窗体及默认部分的绘制信息,接着构建子控件树,源代码如下:
CControlUI* CDialogBuilder::_Parse(CMarkupNode* pRoot, CControlUI* pParent, CPaintManagerUI* pManager)
{
IContainerUI* pContainer = NULL;
CControlUI* pReturn = NULL;
for( CMarkupNode node = pRoot->GetChild() ; node.IsValid(); node = node.GetSibling() ) {
LPCTSTR pstrClass = node.GetName();
if( _tcsicmp(pstrClass, _T("Image")) == 0 || _tcsicmp(pstrClass, _T("Font")) == 0 \
|| _tcsicmp(pstrClass, _T("Default")) == 0 || _tcsicmp(pstrClass, _T("Style")) == 0 ) continue;//这部分已经在上一级函数里初始化过
CControlUI* pControl = NULL;
if (_tcsicmp(pstrClass, _T("Import")) == 0) continue;
if( _tcsicmp(pstrClass, _T("Include")) == 0 ) {//包含其它文件,内存的xml代码,生成控件
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 CreateControl(strClass));
// 检查插件
if( pControl == NULL ) {
CStdPtrArray* pPlugins = CPaintManagerUI::GetPlugins();
LPCREATECONTROL lpCreateControl = NULL;
for( int i = 0; i GetSize(); ++i ) {
lpCreateControl = (LPCREATECONTROL)pPlugins->GetAt(i);
if( lpCreateControl != NULL ) {
pControl = lpCreateControl(pstrClass);
if( pControl != NULL ) break;
}
}
}
// 回掉创建
if( pControl == NULL && m_pCallback != NULL ) {
pControl = m_pCallback->CreateControl(pstrClass);
}
}
if( pControl == NULL ) {
#ifdef _DEBUG
DUITRACE(_T("未知控件:%s"), pstrClass);
#else
continue;
#endif
}
// Add children
if( node.HasChildren() ) {
_Parse(&node, pControl, pManager);
}
// Attach to parent
// 因为某些属性和父窗口相关,比如selected,必须先Add到父窗口
CTreeViewUI* pTreeView = NULL;
if( pParent != NULL && pControl != NULL ) {
CTreeNodeUI* pParentTreeNode = static_cast(pParent->GetInterface(_T("TreeNode")));
CTreeNodeUI* pTreeNode = static_cast(pControl->GetInterface(_T("TreeNode")));
pTreeView = static_cast(pParent->GetInterface(_T("TreeView")));
// TreeNode子节点
if(pTreeNode != NULL) {
if(pParentTreeNode) {
pTreeView = pParentTreeNode->GetTreeView();
if(!pParentTreeNode->Add(pTreeNode)) {
delete pTreeNode;
pTreeNode = NULL;
continue;
}
}
else {
if(pTreeView != NULL) {
if(!pTreeView->Add(pTreeNode)) {
delete pTreeNode;
pTreeNode = NULL;
continue;
}
}
}
}
// TreeNode子控件
else if(pParentTreeNode != NULL) {
pParentTreeNode->GetTreeNodeHoriznotal()->Add(pControl);
}
// 普通控件
else {
if( pContainer == NULL ) pContainer = static_cast(pParent->GetInterface(_T("IContainer")));
ASSERT(pContainer);
if( pContainer == NULL ) return NULL;
//将控件注册到容器内,并将控件与CPaintManagerUI关联起来
//并按名字注册到CPaintManagerUI成员m_mNameHash内。
if( !pContainer->Add(pControl) ) {
delete pControl;
continue;
}
}
}
if( pControl == NULL ) continue;
// 初始化默认属性
if( pManager ) {
if(pTreeView != NULL) {
pControl->SetManager(pManager, pTreeView, true);
}
else {
pControl->SetManager(pManager, NULL, false);
}
LPCTSTR pDefaultAttributes = pManager->GetDefaultAttributeList(pstrClass);
if( pDefaultAttributes ) {
pControl->ApplyAttributeList(pDefaultAttributes);
}
}
// 加载其它属性
if( node.HasAttributes() ) {
TCHAR szValue[500] = { 0 };
SIZE_T cchLen = lengthof(szValue) - 1;
// Set ordinary attributes
int nAttributes = node.GetAttributeCount();
for( int i = 0; i SetAttribute(node.GetAttributeName(i), node.GetAttributeValue(i));
}
}
if( pManager ) {
if(pTreeView == NULL) {
pControl->SetManager(NULL, NULL, false);
}
}
// 返回第一个控件作为根控件
if( pReturn == NULL ) pReturn = pControl;
}
return pReturn;
}
_Parse函数的主要作用是根据xml文件构建ui界面控件树形结构,普通控件直接构建。 【注意】函数返回根控件的指针,再根据根指针往下索引,所以在xml文件Window 标签下第一个容器一定要包含其它子控件和子容器,否则查找函数根据根指针查找会找不到对应的子控件。 另外一方面,其中子控件的构建的方法值得分析下,源码如下:
CDuiString strClass;
strClass.Format(_T("C%sUI"), pstrClass);
pControl = dynamic_cast(CControlFactory::GetInstance()->CreateControl(strClass));
首先通过静态函数::GetInstance()获取一个构建工厂CControlFactory的实例指针,源代码如下所示:
CControlFactory* CControlFactory::GetInstance()
{
static CControlFactory* pInstance = new CControlFactory;
return pInstance;
}
//自定义函数
CControlFactory::CControlFactory()
{
INNER_REGISTER_DUICONTROL(CControlUI);
INNER_REGISTER_DUICONTROL(CContainerUI);
INNER_REGISTER_DUICONTROL(CButtonUI);
INNER_REGISTER_DUICONTROL(CComboUI);
INNER_REGISTER_DUICONTROL(CComboBoxUI);
INNER_REGISTER_DUICONTROL(CDateTimeUI);
INNER_REGISTER_DUICONTROL(CEditUI);
INNER_REGISTER_DUICONTROL(CActiveXUI);
INNER_REGISTER_DUICONTROL(CFlashUI);
INNER_REGISTER_DUICONTROL(CGifAnimUI);
#ifdef USE_XIMAGE_EFFECT
INNER_REGISTER_DUICONTROL(CGifAnimExUI);
#endif
INNER_REGISTER_DUICONTROL(CGroupBoxUI);
INNER_REGISTER_DUICONTROL(CIPAddressUI);
INNER_REGISTER_DUICONTROL(CIPAddressExUI);
INNER_REGISTER_DUICONTROL(CLabelUI);
INNER_REGISTER_DUICONTROL(CListUI);
INNER_REGISTER_DUICONTROL(CListHeaderUI);
INNER_REGISTER_DUICONTROL(CListHeaderItemUI);
INNER_REGISTER_DUICONTROL(CListLabelElementUI);
INNER_REGISTER_DUICONTROL(CListTextElementUI);
INNER_REGISTER_DUICONTROL(CListContainerElementUI);
INNER_REGISTER_DUICONTROL(CMenuUI);
INNER_REGISTER_DUICONTROL(CMenuElementUI);
INNER_REGISTER_DUICONTROL(COptionUI);
INNER_REGISTER_DUICONTROL(CCheckBoxUI);
INNER_REGISTER_DUICONTROL(CProgressUI);
INNER_REGISTER_DUICONTROL(CRichEditUI);
INNER_REGISTER_DUICONTROL(CScrollBarUI);
INNER_REGISTER_DUICONTROL(CSliderUI);
INNER_REGISTER_DUICONTROL(CTextUI);
INNER_REGISTER_DUICONTROL(CTreeNodeUI);
INNER_REGISTER_DUICONTROL(CTreeViewUI);
INNER_REGISTER_DUICONTROL(CWebBrowserUI);
INNER_REGISTER_DUICONTROL(CAnimationTabLayoutUI);
INNER_REGISTER_DUICONTROL(CChildLayoutUI);
INNER_REGISTER_DUICONTROL(CHorizontalLayoutUI);
INNER_REGISTER_DUICONTROL(CTabLayoutUI);
INNER_REGISTER_DUICONTROL(CTileLayoutUI);
INNER_REGISTER_DUICONTROL(CVerticalLayoutUI);
INNER_REGISTER_DUICONTROL(CRollTextUI);
INNER_REGISTER_DUICONTROL(CColorPaletteUI);
INNER_REGISTER_DUICONTROL(CListExUI);
INNER_REGISTER_DUICONTROL(CListContainerHeaderItemUI);
INNER_REGISTER_DUICONTROL(CListTextExtElementUI);
INNER_REGISTER_DUICONTROL(CHotKeyUI);
INNER_REGISTER_DUICONTROL(CFadeButtonUI);
INNER_REGISTER_DUICONTROL(CRingUI);
}
//在常用控件中加上一个在内存中的静态构建函数
#define DECLARE_DUICONTROL(class_name)\
public:\
static CControlUI* CreateControl();
#define IMPLEMENT_DUICONTROL(class_name)\
CControlUI* class_name::CreateControl()\
{ return new class_name; }
#define REGIST_DUICONTROL(class_name)\
CControlFactory::GetInstance()->RegistControl(_T(#class_name), (CreateClass)class_name::CreateControl);
#define INNER_REGISTER_DUICONTROL(class_name)\
RegistControl(_T(#class_name), (CreateClass)class_name::CreateControl);
//注册函数
void CControlFactory::RegistControl(CDuiString strClassName, CreateClass pFunc)
{
strClassName.MakeLower();
m_mapControl.insert(MAP_DUI_CTRATECLASS::value_type(strClassName, pFunc));
}
在每一个子控件中,都添加了如此的构建函数,组成这样一个构建工厂,当外部提供类名动态构建时,调用对应的静态构建函数,动态创建对应的子控件对象,代码如下所示:
typedef CControlUI* (*CreateClass)();
typedef std::map MAP_DUI_CTRATECLASS;
CControlUI* CControlFactory::CreateControl(CDuiString strClassName)
{
strClassName.MakeLower();
MAP_DUI_CTRATECLASS::iterator iter = m_mapControl.find(strClassName);
if ( iter == m_mapControl.end()) {
return NULL;
}
else {
return (CControlUI*) (iter->second());//val作为函数调用。
}
}
到此,根据xml文件创建子控件树,并返回根节点指针介绍完毕!下一小节回到窗口初始化函数部分。
2.作者答疑如有疑问,请留言。