关于duilib中的list的扩展探索
原文地址:http://blog.csdn.net/tragicguy/article/details/21893065
今天在做一个程序的界面时,需要在一个列表中显示除文字以外的其他控件,如:Edit、Button、Combo等;我做界面使用的是duilib,其自带的CListUI并不能满足此项功能,需要进行扩展,在此记录,以便后续使用需要。
先看一下实现的效果:
今天我们的扩展主要包含如下部分:
1. 表头支持控件
在ListUI中,表头是CListHeaderItemUI,而这个类是从CControlUI继承而来,为了能支持在其中显示其他控件,它需要是一个窗口,那么需要将其父类改成CContainerUI,调整基类后,需要同时将CListHeaderItemUI类中引用 CControlUI的地方全部改成CContainerUI,如:
- LPVOID CListHeaderItemUI::GetInterface(LPCTSTR pstrName)
- {
- if( _tcscmp(pstrName, DUI_CTR_LISTHEADERITEM) == 0 ) return this;
- return CContainerUI::GetInterface(pstrName);
- }
如果此处不改,将无法从XML文件中加载内嵌控件。
还需要修改其他如DoEvent事件中的CControlUI,否则会导致表头无法拖拉,切记。
改造后,我们可以从XML文件加载了,XML文件可以这样写:
- <List name="listex" bkcolor="#FFFFFFFF" inset="0,0,0,0" itemshowhtml="true" vscrollbar="true" hscrollbar="true" headerbkimage="file='list_header_bg.png'" itemhotimage="file='tree_hot.bmp' corner='2,1,2,1'" itemselectedimage="file='tree_select.bmp' corner='2,1,2,1'" itemalign="center" itembkcolor="#FFE2DDDF" itemaltbk="true" hscrollbar="false" menu="true">
- <ListHeader height="24" menu="true">
- <ListHeaderItem text="" inset="1,0,1,0" minwidth="60" endellipsis="true" font="1" width="95" normalimage="headerctrl_normal.bmp" hotimage="headerctrl_hot.bmp" pushedimage="headerctrl_down.bmp" sepimage="Headerctrl_Sperator.bmp" sepwidth="2">
- <VerticalLayout inset="1,0,5,0">
- <CheckBox name="selall" endellipsis="true" text="全选" textcolor="#FF386382" hottextcolor="#FF386382" selectedtextcolor="#FF386382" disabledtextcolor="#FFbac0c5" textpadding="20,3,0,0" align="left" selectedimage="file='checkbox_p.png' dest='0,2,15,17'" normalimage="file='checkbox_h.png' dest='0,2,15,17'" />
- </VerticalLayout>
- </ListHeaderItem>
- <ListHeaderItem text="域名" minwidth="100" endellipsis="true" font="1" width="200" normalimage="headerctrl_normal.bmp" hotimage="headerctrl_hot.bmp" pushedimage="headerctrl_down.bmp" sepimage="Headerctrl_Sperator.bmp" sepwidth="2"/>
- <ListHeaderItem text="描述" minwidth="120" endellipsis="true" font="1" width="150" normalimage="headerctrl_normal.bmp" hotimage="headerctrl_hot.bmp" pushedimage="headerctrl_down.bmp" sepimage="Headerctrl_Sperator.bmp" sepwidth="2"/>
- </ListHeader>
这样显示出来的效果如下:
注意:
此处需要将内嵌控件的ListHeaderItem 添加一个inset属性,控制内嵌的控件不要铺满整个ListHeaderItem ,否则表头拖动不了,如:
ListHeaderItem text="" inset="1,0,1,0"
2. 列表项支持控件
CListUI的某一行CListContainerElementUI继承至容器CContainerUI,这样一来我们只需要将需要的控件添加到此容器中,即可正确的显示相关的控件了,此处并不需要做调整,只是这样一来会带来一个问题,那就是所添加的列的宽度无法与表头的宽度保持一致。
要解决这个问题,需要给CListContainerElementUI添加SetPos函数,在此函数中,重新校正数据列宽与表头宽度一致,具体如下:
- void SetPos(RECT rc)
- {
- CContainerUI::SetPos(rc);
- if( m_pOwner == NULL ) return;
- if (m_pHeader == NULL)
- {
- return;
- }
- TListInfoUI* pInfo = m_pOwner->GetListInfo();
- int nCount = m_items.GetSize();
- for (int i = 0; i < nCount; i++)
- {
- CControlUI *pHorizontalLayout = static_cast<CControlUI*>(m_items[i]);
- // if (pHorizontalLayout != NULL)
- // {
- // RECT rtHeader = pHeaderItem->GetPos();
- // RECT rt = pHorizontalLayout->GetPos();
- // rt.left = pInfo->rcColumn[i].left;
- // rt.right = pInfo->rcColumn[i].right;
- // pHorizontalLayout->SetPos(rt);
- // }
- CListHeaderItemUI *pHeaderItem = static_cast<CListHeaderItemUI*>(m_pHeader->GetItemAt(i));
- if (pHorizontalLayout != NULL && pHeaderItem != NULL)
- {
- RECT rtHeader = pHeaderItem->GetPos();
- RECT rt = pHorizontalLayout->GetPos();
- rt.left = rtHeader.left;
- rt.right = rtHeader.right;
- pHorizontalLayout->SetPos(rt);
- }
- }
- }
- CListHeaderUI *m_pHeader;
此处往列表项中添加了表头的指针,需要在插入一行的时候,将表头的指针传递进来,用于在SetPos的时候获取表头宽度。
注意以上代码中的注释部分,原本打算从TListInfoUI的rcColumn中获取表头项宽度的,但发现新添加行时,rcCulumn中的值全是0,需要在插入行前主动调用一次CListUI::SetPos(GetPos());才能正常,使用起来较麻烦,且容易忘记;即使是添加上了,测试发现获取到的位置有一定的偏移,所以采用将Header传入,实时获取了。
以下是一行数据的XML文件描述:
- <?xml version="1.0" encoding="UTF-8"?>
- <Window>
- <ListContainerElement >
- <CheckBox name="selectme" endellipsis="true" text="亲,选我吧!" textcolor="#FF386382" hottextcolor="#FF386382" selectedtextcolor="#FF386382" disabledtextcolor="#FFbac0c5" textpadding="20,3,0,0" align="left" selectedimage="file='checkbox_p.png' dest='0,2,15,17'" normalimage="file='checkbox_h.png' dest='0,2,15,17'" />
- <HorizontalLayout inset="4,4,4,4">
- <Edit text="测试文本" bordersize="1" height="20" bordercolor="#FF4775CC" name="domain" ></Edit>
- </HorizontalLayout>
- <HorizontalLayout >
- <VerticalLayout>
- <Button text="按钮1" width="50" pushedimage="button_down.bmp" hotimage="button_over.bmp" normalimage="button_nor.bmp" name="ttt" ></Button>
- <Button text="按钮2" width="50" pushedimage="button_down.bmp" hotimage="button_over.bmp" normalimage="button_nor.bmp" name="ttt" ></Button>
- <Label text="这是从XML文件中加载的列表项"></Label>
- </VerticalLayout>
- </HorizontalLayout>
- </ListContainerElement>
- </Window>
注意,此处需要确保ListContainerElement 的子控件个数不少于列表的列数
在代码中加载此XML文件,将行数据添加到列表中:
- CListUIEx *pList = static_cast<CListUIEx*>(m_PaintManager.FindControl(_T("listex")));
- CDialogBuilder builder;
- CListContainerElementUI* pLine = (CListContainerElementUI*)(builder.Create(_T("sigle_list_item_column.xml"),(UINT)0, this));
- if( pLine != NULL )
- {
- pList->InsertItem(0, 60, pLine); //此函数是经过二次封装的
- }
加载的效果如下:
这样我们可以在列表的不同项中显示任意内容,甚至是一个完整的窗口了。
3. 通过代码动态添加列及列表项
以上的处理均是调整后从XML加载相应的加载已经配置好的列表进行显示,在完成上述工作后,我这边进一步封装了几个函数,以便于动态的添加列[指定内嵌控件]、动态的插入行以及动态的在某一行列中添加控件。
1). 以下代码用于动态的添加列:
- BOOL CListUIEx::InsertColumn(
- int nCol,
- CListHeaderItemUI *pHeaderItem
- )
- {
- CListHeaderUI *pHeader = CListUI::GetHeader();
- if (pHeader == NULL)
- {
- return FALSE;
- }
- if (pHeader->AddAt(pHeaderItem, nCol))
- {
- return TRUE;
- }
- delete pHeaderItem;
- pHeaderItem = NULL;
- return FALSE;
- }
- BOOL CListUIEx::SetHeaderItemData(int nColumn, CControlUI* pControl)
- {
- CListHeaderUI *pHeader = CListUI::GetHeader();
- if (pHeader == NULL)
- {
- return FALSE;
- }
- CListHeaderItemUI *pHeaderItem = (CListHeaderItemUI *)pHeader->GetItemAt(nColumn);
- pHeaderItem->Add(pControl);
- }
调用代码如下[添加一列,并且向此列中嵌入一个CheckBox]:
- CListHeaderItemUI *pHeaderItem = new CListHeaderItemUI;
- pHeaderItem->SetTextStyle(DT_RIGHT|DT_VCENTER|DT_SINGLELINE);
- pHeaderItem->SetText("新增列 ");
- pHeaderItem->SetAttribute(_T("sepimage"), _T("Headerctrl_Sperator.bmp"));
- pHeaderItem->SetAttribute(_T("sepwidth"), _T("1"));
- pHeaderItem->SetAttribute(_T("pushedimage"), _T("headerctrl_down.bmp"));
- pHeaderItem->SetAttribute(_T("hotimage"), _T("headerctrl_hot.bmp"));
- pHeaderItem->SetAttribute(_T("normalimage"), _T("headerctrl_normal.bmp"));
- pHeaderItem->SetFixedWidth(150);
- pList->InsertColumn(3, pHeaderItem);
- CCheckBoxUI *pBtnUI = new CCheckBoxUI;
- pBtnUI->SetText("选择");
- pBtnUI->SetAttribute(_T("selectedimage"), _T("file='checkbox_p.png' dest='0,2,15,17'"));
- pBtnUI->SetAttribute(_T("normalimage"), _T("file='checkbox_h.png' dest='0,2,15,17'"));
- pBtnUI->SetAttribute(_T("textpadding"), _T("20,3,0,0"));
- pBtnUI->SetAttribute(_T("align"), _T("right"));
- pBtnUI->SetFloat(true);
- pBtnUI->SetAttribute("pos", "20,3, 65, 20");
- pList->SetHeaderItemData(3, pBtnUI);
2). 以下代码用于动态的添加行,动态的指定一列的内容:
- int CListUIEx::InsertItem(int nItem, int nHeight)
- {
- CListContainerElementUIEx *pListItem = new CListContainerElementUIEx;
- pListItem->SetFixedHeight(nHeight);/*固定一个行高*/
- pListItem->SetList(this);
- CListHeaderUI *pHeader = CListUI::GetHeader();
- if (NULL != pHeader)
- {
- int nHeaderCount = pHeader->GetCount();
- for (int i = 0; i < nHeaderCount; i++)
- {
- pListItem->InsertColumn(i);
- }
- }
- if ( !CListUI::AddAt(pListItem, nItem) )
- {
- delete pListItem;
- pListItem = NULL;
- return -1;
- }
- return nItem;
- }
- void CListUIEx::SetItemData(int nItem,
- int nColumn,
- LPCTSTR Text, LPCTSTR Name)
- {
- //存放文本
- CHorizontalLayoutUI *pSubHor = GetListSubItem(nItem, nColumn);
- CLabelUI *pLabel = new CLabelUI;
- pLabel->SetText(Text);//控件属性就根据需求设置吧,我简单设置一下
- pLabel->SetTextStyle(DT_CENTER);
- pLabel->SetAttribute("endellipsis", "true");
- pSubHor->SetAttribute("inset", "3,1,3,1");
- pLabel->SetName(Name);
- pSubHor->Add(pLabel);//添加到父控件
- }
- void CListUIEx::SetItemData(int nItem, int nColumn,CControlUI* pControl)
- {
- CHorizontalLayoutUI *pSubHor = GetListSubItem(nItem, nColumn);
- pSubHor->SetAttribute("inset", "3,0,3,1");
- pSubHor->Add(pControl);//添加到父控件
- }
通过如下代码来添加一行数据:
- CListUIEx *pList = static_cast<CListUIEx*>(m_PaintManager.FindControl(_T("listex")));
- int nIndex = pList->GetCount();
- pList->InsertItem(nIndex);
- CEditUI *pControl = new CEditUI;
- pControl->SetText("");
- pControl->SetName("edit");
- pControl->SetBorderColor(RGB(255, 0, 0));
- pControl->SetAttribute("bordersize", "1");
- pControl->SetAttribute("bordercolor", "#FF4775CC");
- pList->SetItemData(nIndex, 0, pControl);
- CButtonUI *pBtnUI = new CButtonUI;
- pBtnUI->SetText("添加");
- pBtnUI->SetFixedWidth(60);
- pBtnUI->SetAttribute(_T("pushedimage"), _T("button_down.bmp"));
- pBtnUI->SetAttribute(_T("hotimage"), _T("button_over.bmp"));
- pBtnUI->SetAttribute(_T("normalimage"), _T("button_nor.bmp"));
- pList->SetItemData(nIndex, 1, pBtnUI);
- pList->SetItemData(nIndex, 2, "这是一行动态添加的数据", "testid");
- if (pList->GetHeader()->GetCount() > 3)
- {
- pList->SetItemData(nIndex, 3, "新增列数据", "testid1");
- }
至此,ListUI的扩展就告一段落了,目前已经完全满足了的使用需求,相信也能满足绝大部分其他人的需求了,测试程序的完整效果图如下:
测试程序代码下载地址:http://download.csdn.net/detail/tragicguy/7087559
后记:
扩展此控件,参考了文章:http://blog.csdn.net/xdrt81y/article/details/17588961
此份测试代码改自 群友 【朗】 的 ListExtension.
同时特别感谢群友 tojen 的帮助!
duilib功能确实很强大,给我这种UI小白带来了希望,希望有越来越多的高级控件能纳入的基础源码库中,方便大众;也希望其他扩展过duilib功能的大侠,放出代码来,造福众人。
关于duilib中的list的扩展探索的更多相关文章
- Duilib中Webbrowser事件完善使其支持判断页面加载完毕
在多iframe的页面中,需要结合DISPID_DOCUMENTCOMPLETE和DISPID_NAVIGATECOMPLETE2两个事件判断页面是否加载完毕,而duilib中没有提供对DISPID_ ...
- C++中extern “C”含义深层探索
C++中extern “C”含义深层探索 extern “C” 是一个双向都需要用到的语法表示,就是说在cpp引用c头文件,或者c引用cpp文件时都需要用到.但extern “C” 永远只能在cpp引 ...
- ExtJS学习-----------Ext.String,ExtJS对javascript中的String的扩展
关于ExtJS对javascript中的String的扩展,能够參考其帮助文档,文档下载地址:http://download.csdn.net/detail/z1137730824/7748893 以 ...
- (转)C++中extern “C”含义深层探索
(转)C++中extern “C”含义深层探索 转自: http://www.cppblog.com/Macaulish/archive/2008/06/17/53689.html 1.引言 C++语 ...
- ExtJS学习-----------Ext.Array,ExtJS对javascript中的Array的扩展
关于ExtJS对javascript中的Array的扩展.能够參考其帮助文档,文档下载地址:http://download.csdn.net/detail/z1137730824/7748893 因为 ...
- ExtJS学习-----------Ext.Number,ExtJS对javascript中的Number的扩展
关于ExtJS对javascript中的Number的扩展,能够參考其帮助文档,文档下载地址:http://download.csdn.net/detail/z1137730824/7748893 以 ...
- duilib中edit获得鼠标焦点后右边框被覆盖
转载:http://www.cnblogs.com/minggong/p/6457734.html 用duilib做了一个窗口,窗口内有一个供用户输入使用的是edit控件. XML中是这样写的: &l ...
- C#中如果类的扩展方法和类本身的方法签名相同,那么会优先调用类本身的方法
新建一个.NET Core项目,假如我们有如下代码: using System; namespace MethodOverload { static class DemoExtension { pub ...
- 解决方案--duilib中edit获得鼠标焦点后右边框被覆盖
用duilib做了一个登录框,用户名的输入使用的是edit控件. XML中是这样写的: <Edit name="subdomain_edit" tipvalue=" ...
随机推荐
- 使用ajax()方法加载服务器数据
使用ajax()方法加载服务器数据 使用ajax()方法是最底层.功能最强大的请求服务器数据的方法,它不仅可以获取服务器返回的数据,还能向服务器发送请求并传递数值,它的调用格式如下: jQuery.a ...
- 李洪强iOS开之【零基础学习iOS开发】【02-C语言】04-常量、变量
在我们使用计算机的过程中,会接触到各种各样的数据,有文档数据.图片数据.视频数据,还有聊QQ时产生的文字数据.用迅雷下载的文件数据等.这讲我们就来介绍C语言中数据的处理. 一.数据的存储 1.数据类型 ...
- [OOD]违反里氏替换原则的解决方案
关于OOD中的里氏替换原则,大家耳熟能祥了,不再展开,可以参考设计模式的六大设计原则之里氏替换原则.这里尝试讨论常常违反的两种形式和解决方案. 违反里氏替换原则的根源是对子类及父类关系不明确.我们在设 ...
- JavaMail如何保证邮件发送成功
使用过JavaMail的api发送邮件的人可能会有这样一个疑惑:我如何知道我调用该api发送的邮件是否成功呢?一般的开放的api给我们调用都会有个返回值或者状态码,来告诉我们执行成功与否.但是Java ...
- 10、JPA_映射双向多对多的关联关系
双向多对多的关联关系 双向多对多的关联关系(抽象成A-B)具体体现:A中有B的集合的引用,同时B中也有对A的集合的引用.A.B两个实体对应的数据表靠一张中间表来建立连接关系. 同时我们还知道,双向多对 ...
- PCL—低层次视觉—点云分割(最小割算法)
1.点云分割的精度 在之前的两个章节里介绍了基于采样一致的点云分割和基于临近搜索的点云分割算法.基于采样一致的点云分割算法显然是意识流的,它只能割出大概的点云(可能是杯子的一部分,但杯把儿肯定没分割出 ...
- [HDOJ2795]Billboard(线段树,单点更新)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2795 题意:w*h的公告板要贴公告,公告是w*1的,每个公告有先后顺序,要使每个公告贴的位置尽可能地高 ...
- 在oracle中where 子句和having子句中的区别
在oracle中where 子句和having子句中的区别 1.where 不能放在GROUP BY 后面 2.HAVING 是跟GROUP BY 连在一起用的,放在GROUP BY 后面,此时的作用 ...
- Android 获取屏幕尺寸与密度
android中获取屏幕的长于宽,参考了网上有很多代码,但结果与实际不符,如我的手机是i9000,屏幕大小是480*800px,得到的结果却为320*533 结果很不靠谱,于是自己写了几行代码,亲 ...
- Qt之进程间通信(共享内存)
简述 上一节中,我们分享下如何利用Windows消息机制来进行不同进程间的通信.但是有很多局限性,比如:不能跨平台,而且必须两个进程同时存在才可以,要么进程A发了消息谁接收呢? 下面我们来分享另外一种 ...
