最近在学习duilib 我操,网上都没啥资料 我就是想知道怎么样在有XML的情况下自定义一个控件,算了,既然网上没有 那么就自己来看源码好了。
首先,这是我第一次写博客- - 依照我语文全校倒数的水平,我觉得会很糟糕。。。
Duilib的简介就不说了= =百度一大堆,然后我想说的是这个库貌似过时了,算了不管这么多。。。先看一点是一点。
首先看duilib的官方类图:
上面写着xml解析继承UI构建,我们先看XML解析函数bool CMarkup::_Parse(LPTSTR& pstrText, ULONG iParent)
其中参数pstrText是当前需要解析的XML文本,iParent解析出来的控件的父控件位置。
例如第一次调用的时候:
pstrText为:
<?xml version="1.0" encoding="UTF-8"?> <Window size="800,600" mininfo="600,400" caption="0,0,0,32" sizebox="4,4,4,4"> <!-- 窗口的初始尺寸(宽800,高600)、窗口的最小尺寸(宽600,高400)、标题栏拖拽区域(高32)、可拖拽边框大小(这里添加sizebox后就可以拖拽边框调整大小了) --> <VerticalLayout name="window" bkcolor="#FFFFFFFF" bkcolor2="#FFAAAAA0" bkcolor3="#00000000"> <!-- 整个窗口的背景色 --> <!-- 标题栏区 --> <HorizontalLayout name="high"> <Button name="minbtn" tooltip="最小化" normalimage=" file='SysBtn\MinNormal.bmp' " hotimage=" file='SysBtn\MinFocus.bmp' " pushedimage=" file='SysBtn\MinFocus.bmp' "/> <Button name="maxbtn" tooltip="最大化" normalimage=" file='SysBtn\MaxNormal.bmp' " hotimage=" file='SysBtn\MaxFocus.bmp' " pushedimage=" file='SysBtn\MaxFocus.bmp' " /> <Button name="restorebtn" visible="false" tooltip="还原" normalimage=" file='SysBtn\StoreNormal.bmp' " hotimage=" file='SysBtn\StoreFocus.bmp' " pushedimage=" file='SysBtn\StoreFocus.bmp' " /> <Button name="closebtn" tooltip="关闭" normalimage=" file='SysBtn\CloseNormal.bmp' " hotimage=" file='SysBtn\CloseFocus.bmp' " pushedimage=" file='SysBtn\CloseFocus.bmp' "/> </HorizontalLayout> <!-- 客户区 --> </VerticalLayout> </Window>
iParent 为 0
还有个概念要普及:
在duilib中,是按照一个一个控件来读,并且存放在一个数组中 ,而且记录他的同级控件以及子控件队列中的第一个 比如:
Window size="800,600" mininfo="600,400" caption="0,0,0,32" sizebox="4,4,4,4" => 序号为0,子控件队列第一个序号为1.
VerticalLayout name="window" bkcolor="#FFFFFFFF" bkcolor2="#FFAAAAA0" bkcolor3="#00000000" => 序号为1,子控件队列第一个序号为2.
HorizontalLayout name="high" =>序号为2,子控件队列第一个序号为3.
Button name="minbtn" tooltip="最小化" normalimage=" file='SysBtn\MinNormal.bmp' " hotimage=" file='SysBtn\MinFocus.bmp' " pushedimage=" file='SysBtn\MinFocus.bmp' " =>序号为3,无子控件,为2控件的子控件队列序号1
Button name="maxbtn" tooltip="最大化" normalimage=" file='SysBtn\MaxNormal.bmp' " hotimage=" file='SysBtn\MaxFocus.bmp' " pushedimage=" file='SysBtn\MaxFocus.bmp' "=>序号为4,无子控件,为2控件的子控件队列序号2
……以此类推
接下来,我们看解析函数:
bool CMarkup::_Parse(LPTSTR& pstrText, ULONG iParent) { _SkipWhitespace(pstrText); ULONG iPrevious = 0; for( ; ; ) { if( *pstrText == _T('\0') && iParent <= 1 ) return true; _SkipWhitespace(pstrText); if( *pstrText != _T('<') ) return _Failed(_T("Expected start tag"), pstrText); if( pstrText[1] == _T('/') ) return true; *pstrText++ = _T('\0'); _SkipWhitespace(pstrText);//获得字符串中最前面一个不是空格以及\0的字符 // Skip comment or processing directive if( *pstrText == _T('!') || *pstrText == _T('?') ) {//跳过注释和说明 TCHAR ch = *pstrText; if( *pstrText == _T('!') ) ch = _T('-'); while( *pstrText != _T('\0') && !(*pstrText == ch && *(pstrText + 1) == _T('>')) ) pstrText = ::CharNext(pstrText); if( *pstrText != _T('\0') ) pstrText += 2; _SkipWhitespace(pstrText); continue; } _SkipWhitespace(pstrText); // Fill out element structure XMLELEMENT* pEl = _ReserveElement();//返回当前控件所存的序号的位置 ULONG iPos = pEl - m_pElements;//获得控件序号 pEl->iStart = pstrText - m_pstrXML;//控件对应的字符串在整个xml中的偏移量,对应着控件字符串的开始。例如Window size="800,600" mininfo="600,400" caption="0,0,0,32" sizebox="4,4,4,4",就为一个控件字符串 // iStart对应着W在xml的偏移量。 pEl->iParent = iParent;//记录该节点的父节点序号 pEl->iNext = pEl->iChild = 0;//平级控件的下一个控件的序号,以及子控件队列中的首控件序号 if( iPrevious != 0 ) m_pElements[iPrevious].iNext = iPos;//如果iPrevious !=0 说明记录的是平级控件 else if( iParent > 0 ) m_pElements[iParent].iChild = iPos;// 如果iPrevious ==0 说明记录的是平级控件队列的第一个,所以该节点的父节点记录子控件队列中的第一个控件序号。 iPrevious = iPos; // Parse name LPCTSTR pstrName = pstrText;//当前控件的类型名称的开头偏移量例如:Window size="800,600" mininfo="600,400" caption="0,0,0,32" sizebox="4,4,4,4" 此时pstrName 记录的是W在xml的偏移量 _SkipIdentifier(pstrText)//跳过控件类型,并将最后一个字符赋值为0 Window0size="800,600" mininfo="600,400" caption="0,0,0,32" sizebox="4,4,4,4"(window后面的空格被赋值为0,代表一个字符串的结尾) LPTSTR pstrNameEnd = pstrText;//记录Window0size 中的s的偏移量 if( *pstrText == _T('\0') ) return _Failed(_T("Error parsing element name"), pstrText); // Parse attributes if( !_ParseAttributes(pstrText) ) return false; //找到一个控件的字符串的最后一个字母的偏移位置 _SkipWhitespace(pstrText); if( pstrText[0] == _T('/') && pstrText[1] == _T('>') )//这种情况下的基本上不会有子节点控件。 { pEl->iData = pstrText - m_pstrXML;//记录下该控件的字符串对应的最后一个字符在xml的偏移量 *pstrText = _T('\0'); pstrText += 2; } else //这种情况下说明是有子控件队列的 { if( *pstrText != _T('>') ) return _Failed(_T("Expected start-tag closing"), pstrText); // Parse node data pEl->iData = ++pstrText - m_pstrXML; //记录下该控件的字符串对应的最后一个字符在xml的偏移量 LPTSTR pstrDest = pstrText; if( !_ParseData(pstrText, pstrDest, _T('<')) ) return false; //跳到最近的'<'的偏移位置,因为字符串解析完后还有>XXXX\n\r<的形式存在,所以直接找到下一个控件的开头的偏移位置 // Determine type of next element if( *pstrText == _T('\0') && iParent <= 1 ) return true;//结束 if( *pstrText != _T('<') ) return _Failed(_T("Expected end-tag start"), pstrText); if( pstrText[0] == _T('<') && pstrText[1] != _T('/') ) { if( !_Parse(pstrText, iPos) ) return false;//对剩下字符串进行递归操作 } if( pstrText[0] == _T('<') && pstrText[1] == _T('/') ) //XML元素结尾检查看是否是相对应的控件闭合。 { *pstrDest = _T('\0'); *pstrText = _T('\0'); pstrText += 2; _SkipWhitespace(pstrText); SIZE_T cchName = pstrNameEnd - pstrName; if( _tcsncmp(pstrText, pstrName, cchName) != 0 ) return _Failed(_T("Unmatched closing tag"), pstrText); pstrText += cchName; _SkipWhitespace(pstrText); if( *pstrText++ != _T('>') ) return _Failed(_T("Unmatched closing tag"), pstrText); } } *pstrNameEnd = _T('\0'); _SkipWhitespace(pstrText); } }
我靠写文章好废时间。不过我确实思路也顺了很多。本来想把xml的都出来的m_pElements对应的控件数组转化成对应的控件,时间不够,明天再说吧- -