最近在学习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对应的控件数组转化成对应的控件,时间不够,明天再说吧- -