大家好,我要介绍的所有知识点都是WINCE/windows触摸屏DUI开源框架constvar(点击下载代码)开发过程中遇到的比较有讨论价值的问题。
本文要讨论的是与界面解析加载相关的XML解析和动态创建界面。
XML是directui界面对象配置文件的最好选择,因为它的树形结构很适合描述同样是树形结构的对话框。从XML中可以很清晰的看清界面元素之间的层次关系。同时用XML可以很方便检测语法错误,以及很容易解析。有很多开源的解析XML的代码,这里我们选用的是CMARKUP。 因为它相当于是一个C++类,直接添加到功能就能很简便的使用。
一般的DUI框架会带一些辅助工具来生成这个XML配置,CONSTVAR也是如此。生成和解析的代码原理大致相似。这里的是解析一个对话框的代码。
动态创建对象则可以参考MFC的动态创建对象的实现,或者是搜索该关键词,相关的文章超多就不再累述了。
//解析res xml
CMarkupxml;
pRes->Parse(xml);
xml.ResetPos();
std::wstringstr;
std::wstringstrAtt;
CRuntimeClass*pCls = NULL;
//根据xml创建界面控件
//第一个结点已存在不需要创建,默认第一个结点为窗体根结点
xml.FindNode(CMarkup::MNT_ELEMENT);
//当前父结点
int nRtn = 0;
VtXmlNode vtNodesTag;
IterXmlNode IterNodesTag,IterPre;
SXmlNode xmlNode;
std::wstring strClsName;
if(pTribe!= m_pRoot)
{
pTribe->SetHeight(1);// 初始界面高度为
}
else
{
pTribe->SetHeight(0);
}
xmlNode.pNode= pTribe;
xmlNode.strTag= xml.GetTagName();
vtNodesTag.push_back(xmlNode);
strAtt= xml.GetAttrib(L"name");
xmlNode.pNode->SetName(strAtt);
xml.ResetPos();
intnRear = 1;
intnHead = 0;
while(nRear> nHead)
{
IterNodesTag= vtNodesTag.begin() + nHead;
if(nHead>= 1)
{
xml.RestorePos(IterNodesTag->strTag.c_str());
}
else
{
if(!xml.FindElem(IterNodesTag->strTag.c_str()))
{
nHead++;
continue;
}
}
xml.IntoElem();
while(1)
{
nRtn= xml.FindNode(CMarkup::MNT_ELEMENT);
if(0== nRtn)
{
break;
}
else
{
//增加会导致之前的iter失效
IterNodesTag= vtNodesTag.begin() + nHead;
xmlNode.strTag= xml.GetTagName();
//保存位置
xml.SavePos(xmlNode.strTag.c_str());
if(xmlNode.strTag.find(L"obj_")== 0)
{
strAtt= xml.GetAttrib(L"type");
//创建结点,并设置它的属性
strClsName= strAtt;
pCls= CRuntimeClass::LoadByName(strClsName);
if(NULL!= pCls)
{
// 动态创建对象
xmlNode.pNode=(CGroup*)pCls->CreateObject();
strAtt= xml.GetAttrib(L"name");
xmlNode.pNode->SetName(strAtt);
xmlNode.pNode->SetClassName(strClsName);
//附加属性
xmlNode.pNode->SetAdditionalAtt(xml);
//添加到父结点
IterNodesTag->pNode->AddNode(xmlNode.pNode);
vtNodesTag.push_back(xmlNode);
nRear++;
}
}
elseif(xmlNode.strTag.compare(L"style")==0)
{
strAtt= xml.GetAttrib(L"xyz");
intx,y,z,w,h;
swscanf(strAtt.c_str(),L"%d,%d,%d",&x,&y,&w,&h,&z);
if(pTribe== IterNodesTag->pNode)
{
//tribe用自己的z
IterNodesTag->pNode->InitPos(x,h,IterNodesTag->pNode->GetZ());
}
else
{
IterNodesTag->pNode->InitPos(x,z);
}
BOOLb;
DWORDdw;
strAtt= xml.GetAttrib(L"visible");
swscanf(strAtt.c_str(),L"%d",&b);
IterNodesTag->pNode->SetVisible(b);
strAtt= xml.GetAttrib(L"enable");
swscanf(strAtt.c_str(),&b);
IterNodesTag->pNode->SetEnable(b);
strAtt= xml.GetAttrib(L"message");
swscanf(strAtt.c_str(),&dw);
IterNodesTag->pNode->SetMsg(dw);
strAtt= xml.GetAttrib(L"alpha");
swscanf(strAtt.c_str(),&b);
IterNodesTag->pNode->SetAlpha(b);
………….
continue;
}
}
}
nHead++;
}
//对象已创建不再重新解析XML
pTribe->SetCreated(TRUE);
比较重要的一点是XML只加载了一遍后下次不再创建对象。这种做法的好处是省了解析XML的时间,但缺点也很明显,因为对象没有析构,对象的状态也就会被保持。即每次进入一个界面的时候都要针对性的初始化控件状态。因为运行之后的控件可能状态已经改变。为了达到像加载时的效果就必须手动初始化。