对于简单的list控件已经有前辈分析了自带demo的ListRes全过程,duilib DirectUI库里面的一个简单的例子ListDemo,
他分析了listdemo的来龙去脉,这里我只是将个人理解的list分析一下。
由于自带的listdemo不能满足要求,所以必须个人扩展list,通过尝试 发现
1. 列表头禁止拖动情况
这种情况很简单, 配置xml的时候将 表头宽度 和 元素宽度设置相同就行了,listheader布局如下:
- <List name="domainlist" bkcolor="#FFFFFFFF" inset="0,0,0,0" itemshowhtml="true" vscrollbar="true" hscrollbar="true" headerbkimage="file='list_header_bg.png'" itemalign="center" itembkcolor="#FFE2DDDF" itemaltbk="true" hscrollbar="false" menu="true">
- <ListHeader height="24" menu="true">
- <ListHeaderItem text="No" font="1" width="130" hotimage="file='list_header_hot.png'" pushedimage="file='list_header_pushed.png'" sepimage="file='list_header_sep.png'" sepwidth="1"/>
- <ListHeaderItem text="Domain" font="1" width="160" hotimage="file='list_header_hot.png'" pushedimage="file='list_header_pushed.png'" sepimage="file='list_header_sep.png'" sepwidth="1"/>
- <ListHeaderItem text="Description" font="1" width="140" hotimage="file='list_header_hot.png'" pushedimage="file='list_header_pushed.png'" sepimage="file='list_header_sep.png'" sepwidth="1"/>
- </ListHeader>
- </List>
上面是listdemo自带的xml,只是将listheaderitem宽度修改了
下面是listelement布局:
- <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
- <Window>
- <HorizontalLayout width="266" height="60" bkcolor="#FFD2D2D2" >
- <HorizontalLayout width="130" height="60" bordersize="1" bordercolor="#FF00FF00">
- <HorizontalLayout />
- <VerticalLayout width="32">
- <HorizontalLayout />
- <Label name="listmem1" text="111" align="center" float="false" bkcolor="#FFFFFFFF" pos="22,0,0,0" width="32" height="18" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" />
- <HorizontalLayout />
- </VerticalLayout>
- <HorizontalLayout />
- </HorizontalLayout>
- <VerticalLayout width="160" height="60" bordersize="1" bordercolor="#FF00FF00">
- <Label name="listmem2" text="222" align="center" float="true" bkcolor="#FFFFFFFF" pos="17,7,0,0" width="51" height="15" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" />
- </VerticalLayout>
- <VerticalLayout width="140" height="60" bordersize="1" bordercolor="#FF00FF00">
- <Edit name="listmem3" text="333" float="true" pos="10,7,0,0" width="61" height="15" bkcolor="#FFFFFFFF" textpadding="4,3,4,3" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" />
- <Button float="true" pos="18,29,0,0" width="72" height="24" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" align="center" normalimage="file='offline_down.png' source='0,0,72,24'" hotimage="file='offline_down.png' source='0,24,72,48'" pushedimage="file='offline_down.png' source='0,48,76,72'" />
- </VerticalLayout>
- </HorizontalLayout>
- </Window>
使用的时候添加代码如下:
我是直接修改listdemo的,
屏蔽原有的OnSearch函数,添加下面代码即可:
- CDialogBuilder builder;
- CVerticalLayoutUI *plist_element = static_cast<CVerticalLayoutUI*>( builder.Create( _T("listmem1.xml") , 0 , NULL , &m_pm , NULL ) );
- CListUI *plist = static_cast< CListUI* >( m_pm.FindControl("domainlist") );
- if ( !plist )
- {
- return ;
- }
- plist->Add(plist_element);
最后启动程序,得到下面的界面
2.列表头可拖动情况
如果直接使用CListContainerElementUI就会出现下面排版了。
可以看到位置完全打乱了,通过源码可以查到位置布局使用的函数是
- void SetPos(RECT rc);
CListContainerElementUI里面并没有这个函数,那就是调用了CContainerUI的SetPos函数
CContainerUI的SetPos函数
- void CContainerUI::SetPos(RECT rc)
- {
- CControlUI::SetPos(rc);
- if( m_items.IsEmpty() ) return;
- rc.left += m_rcInset.left;
- rc.top += m_rcInset.top;
- rc.right -= m_rcInset.right;
- rc.bottom -= m_rcInset.bottom;
- for( int it = 0; it < m_items.GetSize(); it++ ) {
- CControlUI* pControl = static_cast<CControlUI*>(m_items[it]);
- if( !pControl->IsVisible() ) continue;
- if( pControl->IsFloat() ) {
- SetFloatPos(it);
- }
- else {
- pControl->SetPos(rc); // 所有非float子控件放大到整个客户区
- }
- }
- }
直接将得到的rc设置给子控件了,也就是说,ListContainerElement每一列的宽度都是一样的,第二列 被 第三列 覆盖了 ,第一列一直居中。
这里说明一下,duilib 控件位置布局是由父控件设置的,父控件只管自己的子控件。如下图所示
Root只管理下一层的Root1和Root2,其余的和他不相干。
Root1管理Root3和Root4,Root2管理Root5和Root6.
这里的父节点都是IContainerUI控件或者继承于IContainerUI控件的类,叶子节点一般都是CControlUI类或者继承于CControlUI的类。
所以我们需要在ListContainerElement添加SetPos函数
- void CListContainerElementUI::SetPos(RECT rc)
- {
- CControlUI::SetPos(rc);
- rc = m_rcItem;
- // Adjust for inset
- rc.left += m_rcInset.left;
- rc.top += m_rcInset.top;
- rc.right -= m_rcInset.right;
- rc.bottom -= m_rcInset.bottom;
- TListInfoUI *plistinfo = GetOwner()->GetListInfo();
- // Determine the width of elements that are sizeable
- SIZE szAvailable = { rc.right - rc.left, rc.bottom - rc.top };
- for( int it2 = 0; it2 < m_items.GetSize(); it2++ )
- {
- CControlUI* pControl = static_cast<CControlUI*>(m_items[it2]);
- if( !pControl->IsVisible() )
- continue;
- if( pControl->IsFloat() )
- {
- SetFloatPos(it2);
- continue;
- }
- RECT rcPadding = pControl->GetPadding();
- SIZE sz = pControl->EstimateSize(szAvailable);
- if( sz.cx == 0 )
- {
- if( sz.cx < pControl->GetMinWidth() )
- sz.cx = pControl->GetMinWidth();
- if( sz.cx > pControl->GetMaxWidth() )
- sz.cx = pControl->GetMaxWidth();
- }
- else
- {
- if( sz.cx < pControl->GetMinWidth() )
- sz.cx = pControl->GetMinWidth();
- if( sz.cx > pControl->GetMaxWidth() )
- sz.cx = pControl->GetMaxWidth();
- }
- sz.cy = pControl->GetFixedHeight();
- if( sz.cy == 0 )
- sz.cy = rc.bottom - rc.top - rcPadding.top - rcPadding.bottom;
- if( sz.cy < 0 )
- sz.cy = 0;
- if( sz.cy < pControl->GetMinHeight() )
- sz.cy = pControl->GetMinHeight();
- if( sz.cy > pControl->GetMaxHeight() )
- sz.cy = pControl->GetMaxHeight();
- RECT rcCtrl = { plistinfo->rcColumn[it2].left + rcPadding.left,
- rc.top + rcPadding.top,
- plistinfo->rcColumn[it2].right + rcPadding.left,
- rc.top + sz.cy + rcPadding.top + rcPadding.bottom };
- pControl->SetPos(rcCtrl);
- }
- }
这里面代码主要来自于CHorizontalLayoutUI,删除了个人认为不需要的代码,当然本人接触这东西才一个月,也有可能多删除了一些东西。
重新写OnSearch函数
- CDialogBuilder builder;
- CListContainerElementUI *plist_element = static_cast<CListContainerElementUI*>( builder.Create( _T("listmem.xml") , 0 , NULL , &m_pm , NULL ) );
- if ( !plist_element )
- {
- return ;
- }
- if ( !plist )
- {
- return ;
- }
- plist->Add(plist_element);
现在可以看到拖动效果了
直接上图吧,原始图
拖动图