原文地址:http://blog.csdn.net/tragicguy/article/details/21893065

今天在做一个程序的界面时,需要在一个列表中显示除文字以外的其他控件,如:Edit、Button、Combo等;我做界面使用的是duilib,其自带的CListUI并不能满足此项功能,需要进行扩展,在此记录,以便后续使用需要。

先看一下实现的效果:

今天我们的扩展主要包含如下部分:

1. 表头支持控件

在ListUI中,表头是CListHeaderItemUI,而这个类是从CControlUI继承而来,为了能支持在其中显示其他控件,它需要是一个窗口,那么需要将其父类改成CContainerUI,调整基类后,需要同时将CListHeaderItemUI类中引用 CControlUI的地方全部改成CContainerUI,如:

  1. LPVOID CListHeaderItemUI::GetInterface(LPCTSTR pstrName)
  2. {
  3. if( _tcscmp(pstrName, DUI_CTR_LISTHEADERITEM) == 0 ) return this;
  4. return CContainerUI::GetInterface(pstrName);
  5. }

如果此处不改,将无法从XML文件中加载内嵌控件。

还需要修改其他如DoEvent事件中的CControlUI,否则会导致表头无法拖拉,切记。

改造后,我们可以从XML文件加载了,XML文件可以这样写:

[html] view
plain
copy

  1. <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">
  2. <ListHeader height="24" menu="true">
  3. <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">
  4. <VerticalLayout inset="1,0,5,0">
  5. <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'"  />
  6. </VerticalLayout>
  7. </ListHeaderItem>
  8. <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"/>
  9. <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"/>
  10. </ListHeader>

这样显示出来的效果如下:

注意:

此处需要将内嵌控件的ListHeaderItem 添加一个inset属性,控制内嵌的控件不要铺满整个ListHeaderItem ,否则表头拖动不了,如:

ListHeaderItem text="" inset="1,0,1,0"

2. 列表项支持控件

CListUI的某一行CListContainerElementUI继承至容器CContainerUI,这样一来我们只需要将需要的控件添加到此容器中,即可正确的显示相关的控件了,此处并不需要做调整,只是这样一来会带来一个问题,那就是所添加的列的宽度无法与表头的宽度保持一致。

要解决这个问题,需要给CListContainerElementUI添加SetPos函数,在此函数中,重新校正数据列宽与表头宽度一致,具体如下:

  1. void SetPos(RECT rc)
  2. {
  3. CContainerUI::SetPos(rc);
  4. if( m_pOwner == NULL ) return;
  5. if (m_pHeader == NULL)
  6. {
  7. return;
  8. }
  9. TListInfoUI* pInfo = m_pOwner->GetListInfo();
  10. int nCount = m_items.GetSize();
  11. for (int i = 0; i < nCount; i++)
  12. {
  13. CControlUI *pHorizontalLayout = static_cast<CControlUI*>(m_items[i]);
  14. // if (pHorizontalLayout != NULL)
  15. // {
  16. // RECT rtHeader = pHeaderItem->GetPos();
  17. // RECT rt = pHorizontalLayout->GetPos();
  18. // rt.left = pInfo->rcColumn[i].left;
  19. // rt.right = pInfo->rcColumn[i].right;
  20. // pHorizontalLayout->SetPos(rt);
  21. // }
  22. CListHeaderItemUI *pHeaderItem = static_cast<CListHeaderItemUI*>(m_pHeader->GetItemAt(i));
  23. if (pHorizontalLayout != NULL && pHeaderItem != NULL)
  24. {
  25. RECT rtHeader = pHeaderItem->GetPos();
  26. RECT rt = pHorizontalLayout->GetPos();
  27. rt.left = rtHeader.left;
  28. rt.right = rtHeader.right;
  29. pHorizontalLayout->SetPos(rt);
  30. }
  31. }
  32. }
  33. CListHeaderUI *m_pHeader;

此处往列表项中添加了表头的指针,需要在插入一行的时候,将表头的指针传递进来,用于在SetPos的时候获取表头宽度。

注意以上代码中的注释部分,原本打算从TListInfoUI的rcColumn中获取表头项宽度的,但发现新添加行时,rcCulumn中的值全是0,需要在插入行前主动调用一次CListUI::SetPos(GetPos());才能正常,使用起来较麻烦,且容易忘记;即使是添加上了,测试发现获取到的位置有一定的偏移,所以采用将Header传入,实时获取了。

以下是一行数据的XML文件描述:

[html] view
plain
copy

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <Window>
  3. <ListContainerElement >
  4. <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'"  />
  5. <HorizontalLayout inset="4,4,4,4">
  6. <Edit text="测试文本" bordersize="1" height="20" bordercolor="#FF4775CC" name="domain" ></Edit>
  7. </HorizontalLayout>
  8. <HorizontalLayout >
  9. <VerticalLayout>
  10. <Button text="按钮1" width="50" pushedimage="button_down.bmp" hotimage="button_over.bmp" normalimage="button_nor.bmp" name="ttt" ></Button>
  11. <Button text="按钮2" width="50" pushedimage="button_down.bmp" hotimage="button_over.bmp" normalimage="button_nor.bmp" name="ttt" ></Button>
  12. <Label text="这是从XML文件中加载的列表项"></Label>
  13. </VerticalLayout>
  14. </HorizontalLayout>
  15. </ListContainerElement>
  16. </Window>

注意,此处需要确保ListContainerElement 的子控件个数不少于列表的列数

在代码中加载此XML文件,将行数据添加到列表中:

  1. CListUIEx *pList = static_cast<CListUIEx*>(m_PaintManager.FindControl(_T("listex")));
  2. CDialogBuilder builder;
  3. CListContainerElementUI* pLine = (CListContainerElementUI*)(builder.Create(_T("sigle_list_item_column.xml"),(UINT)0, this));
  4. if( pLine != NULL )
  5. {
  6. pList->InsertItem(0, 60, pLine); //此函数是经过二次封装的
  7. }

加载的效果如下:

这样我们可以在列表的不同项中显示任意内容,甚至是一个完整的窗口了。

3. 通过代码动态添加列及列表项

以上的处理均是调整后从XML加载相应的加载已经配置好的列表进行显示,在完成上述工作后,我这边进一步封装了几个函数,以便于动态的添加列[指定内嵌控件]、动态的插入行以及动态的在某一行列中添加控件。

1). 以下代码用于动态的添加列:

  1. BOOL CListUIEx::InsertColumn(
  2. int nCol,
  3. CListHeaderItemUI *pHeaderItem
  4. )
  5. {
  6. CListHeaderUI *pHeader = CListUI::GetHeader();
  7. if (pHeader == NULL)
  8. {
  9. return FALSE;
  10. }
  11. if (pHeader->AddAt(pHeaderItem, nCol))
  12. {
  13. return TRUE;
  14. }
  15. delete pHeaderItem;
  16. pHeaderItem = NULL;
  17. return FALSE;
  18. }
  19. BOOL CListUIEx::SetHeaderItemData(int nColumn, CControlUI* pControl)
  20. {
  21. CListHeaderUI *pHeader = CListUI::GetHeader();
  22. if (pHeader == NULL)
  23. {
  24. return FALSE;
  25. }
  26. CListHeaderItemUI *pHeaderItem = (CListHeaderItemUI *)pHeader->GetItemAt(nColumn);
  27. pHeaderItem->Add(pControl);
  28. }

调用代码如下[添加一列,并且向此列中嵌入一个CheckBox]:

  1. CListHeaderItemUI *pHeaderItem = new CListHeaderItemUI;
  2. pHeaderItem->SetTextStyle(DT_RIGHT|DT_VCENTER|DT_SINGLELINE);
  3. pHeaderItem->SetText("新增列  ");
  4. pHeaderItem->SetAttribute(_T("sepimage"), _T("Headerctrl_Sperator.bmp"));
  5. pHeaderItem->SetAttribute(_T("sepwidth"), _T("1"));
  6. pHeaderItem->SetAttribute(_T("pushedimage"), _T("headerctrl_down.bmp"));
  7. pHeaderItem->SetAttribute(_T("hotimage"), _T("headerctrl_hot.bmp"));
  8. pHeaderItem->SetAttribute(_T("normalimage"), _T("headerctrl_normal.bmp"));
  9. pHeaderItem->SetFixedWidth(150);
  10. pList->InsertColumn(3, pHeaderItem);
  11. CCheckBoxUI *pBtnUI = new CCheckBoxUI;
  12. pBtnUI->SetText("选择");
  13. pBtnUI->SetAttribute(_T("selectedimage"), _T("file='checkbox_p.png' dest='0,2,15,17'"));
  14. pBtnUI->SetAttribute(_T("normalimage"), _T("file='checkbox_h.png' dest='0,2,15,17'"));
  15. pBtnUI->SetAttribute(_T("textpadding"), _T("20,3,0,0"));
  16. pBtnUI->SetAttribute(_T("align"), _T("right"));
  17. pBtnUI->SetFloat(true);
  18. pBtnUI->SetAttribute("pos", "20,3, 65, 20");
  19. pList->SetHeaderItemData(3, pBtnUI);

2). 以下代码用于动态的添加行,动态的指定一列的内容:

  1. int CListUIEx::InsertItem(int nItem, int nHeight)
  2. {
  3. CListContainerElementUIEx *pListItem = new CListContainerElementUIEx;
  4. pListItem->SetFixedHeight(nHeight);/*固定一个行高*/
  5. pListItem->SetList(this);
  6. CListHeaderUI *pHeader = CListUI::GetHeader();
  7. if (NULL != pHeader)
  8. {
  9. int nHeaderCount = pHeader->GetCount();
  10. for (int i = 0; i < nHeaderCount; i++)
  11. {
  12. pListItem->InsertColumn(i);
  13. }
  14. }
  15. if ( !CListUI::AddAt(pListItem, nItem) )
  16. {
  17. delete pListItem;
  18. pListItem = NULL;
  19. return -1;
  20. }
  21. return nItem;
  22. }
  23. void CListUIEx::SetItemData(int nItem,
  24. int nColumn,
  25. LPCTSTR Text, LPCTSTR Name)
  26. {
  27. //存放文本
  28. CHorizontalLayoutUI *pSubHor = GetListSubItem(nItem, nColumn);
  29. CLabelUI *pLabel = new CLabelUI;
  30. pLabel->SetText(Text);//控件属性就根据需求设置吧,我简单设置一下
  31. pLabel->SetTextStyle(DT_CENTER);
  32. pLabel->SetAttribute("endellipsis", "true");
  33. pSubHor->SetAttribute("inset", "3,1,3,1");
  34. pLabel->SetName(Name);
  35. pSubHor->Add(pLabel);//添加到父控件
  36. }
  37. void CListUIEx::SetItemData(int nItem, int nColumn,CControlUI* pControl)
  38. {
  39. CHorizontalLayoutUI *pSubHor = GetListSubItem(nItem, nColumn);
  40. pSubHor->SetAttribute("inset", "3,0,3,1");
  41. pSubHor->Add(pControl);//添加到父控件
  42. }

通过如下代码来添加一行数据:

  1. CListUIEx *pList = static_cast<CListUIEx*>(m_PaintManager.FindControl(_T("listex")));
  2. int nIndex = pList->GetCount();
  3. pList->InsertItem(nIndex);
  4. CEditUI *pControl = new CEditUI;
  5. pControl->SetText("");
  6. pControl->SetName("edit");
  7. pControl->SetBorderColor(RGB(255, 0, 0));
  8. pControl->SetAttribute("bordersize", "1");
  9. pControl->SetAttribute("bordercolor", "#FF4775CC");
  10. pList->SetItemData(nIndex, 0, pControl);
  11. CButtonUI *pBtnUI = new CButtonUI;
  12. pBtnUI->SetText("添加");
  13. pBtnUI->SetFixedWidth(60);
  14. pBtnUI->SetAttribute(_T("pushedimage"), _T("button_down.bmp"));
  15. pBtnUI->SetAttribute(_T("hotimage"), _T("button_over.bmp"));
  16. pBtnUI->SetAttribute(_T("normalimage"), _T("button_nor.bmp"));
  17. pList->SetItemData(nIndex, 1, pBtnUI);
  18. pList->SetItemData(nIndex, 2, "这是一行动态添加的数据", "testid");
  19. if (pList->GetHeader()->GetCount() > 3)
  20. {
  21. pList->SetItemData(nIndex, 3, "新增列数据", "testid1");
  22. }

至此,ListUI的扩展就告一段落了,目前已经完全满足了的使用需求,相信也能满足绝大部分其他人的需求了,测试程序的完整效果图如下:

测试程序代码下载地址:http://download.csdn.net/detail/tragicguy/7087559

后记:

扩展此控件,参考了文章:http://blog.csdn.net/xdrt81y/article/details/17588961

此份测试代码改自 群友 【朗】 的 ListExtension.

同时特别感谢群友 tojen 的帮助!

duilib功能确实很强大,给我这种UI小白带来了希望,希望有越来越多的高级控件能纳入的基础源码库中,方便大众;也希望其他扩展过duilib功能的大侠,放出代码来,造福众人。

关于duilib中的list的扩展探索的更多相关文章

  1. Duilib中Webbrowser事件完善使其支持判断页面加载完毕

    在多iframe的页面中,需要结合DISPID_DOCUMENTCOMPLETE和DISPID_NAVIGATECOMPLETE2两个事件判断页面是否加载完毕,而duilib中没有提供对DISPID_ ...

  2. C++中extern “C”含义深层探索

    C++中extern “C”含义深层探索 extern “C” 是一个双向都需要用到的语法表示,就是说在cpp引用c头文件,或者c引用cpp文件时都需要用到.但extern “C” 永远只能在cpp引 ...

  3. ExtJS学习-----------Ext.String,ExtJS对javascript中的String的扩展

    关于ExtJS对javascript中的String的扩展,能够參考其帮助文档,文档下载地址:http://download.csdn.net/detail/z1137730824/7748893 以 ...

  4. (转)C++中extern “C”含义深层探索

    (转)C++中extern “C”含义深层探索 转自: http://www.cppblog.com/Macaulish/archive/2008/06/17/53689.html 1.引言 C++语 ...

  5. ExtJS学习-----------Ext.Array,ExtJS对javascript中的Array的扩展

    关于ExtJS对javascript中的Array的扩展.能够參考其帮助文档,文档下载地址:http://download.csdn.net/detail/z1137730824/7748893 因为 ...

  6. ExtJS学习-----------Ext.Number,ExtJS对javascript中的Number的扩展

    关于ExtJS对javascript中的Number的扩展,能够參考其帮助文档,文档下载地址:http://download.csdn.net/detail/z1137730824/7748893 以 ...

  7. duilib中edit获得鼠标焦点后右边框被覆盖

    转载:http://www.cnblogs.com/minggong/p/6457734.html 用duilib做了一个窗口,窗口内有一个供用户输入使用的是edit控件. XML中是这样写的: &l ...

  8. C#中如果类的扩展方法和类本身的方法签名相同,那么会优先调用类本身的方法

    新建一个.NET Core项目,假如我们有如下代码: using System; namespace MethodOverload { static class DemoExtension { pub ...

  9. 解决方案--duilib中edit获得鼠标焦点后右边框被覆盖

    用duilib做了一个登录框,用户名的输入使用的是edit控件. XML中是这样写的: <Edit name="subdomain_edit" tipvalue=" ...

随机推荐

  1. 解决在windows的eclipse上面运行WordCount程序出现的一系列问题详解

    一.简介 要在Windows下的 Eclipse上调试Hadoop2代码,所以我们在windows下的Eclipse配置hadoop-eclipse-plugin- 2.6.0.jar插件,并在运行H ...

  2. 【Linux高频命令专题(6)】mkdir

    简述 用来创建指定的名称的目录,要求创建目录的用户在当前目录中具有写权限,并且指定的目录名不能是当前目录中已有的目录. 命令格式 mkdir [选项] 目录... 命令参数 -m, --mode=模式 ...

  3. QT5删除隐藏目录+隐藏文件(使用Process::start函数调用系统命令,且等待到结束)

    1.功能需求 删除一个目录(包括目录本身),同时删除该目录中所有文件及目录(含隐藏的) 2.遇到的问题 qt5中已经有了递归删除目录的函数--->bool QDir::removeRecursi ...

  4. 手动安装UniDAC的过程

    每次安装都不一样,而且有时候挺麻烦的,所以记下来.我这次安装过程是这样的: 0. 修改Source\Delphi7\Make.bat,填入正确的IdeDir 1.找到source\delphi7目录, ...

  5. 喵星人教你记 HTTP 状态码

    记忆HTTP状态码是有一些困难的,因为状态码很多且很难记忆.GirlieMac,也就是Tomomi Imura利用她巧妙的构思,PS了一系列的HTTP状态信息.在你看过这些图片之后,你绝对可以记住一些 ...

  6. Android viewPage notifyDataSetChanged无刷新

    转载 http://www.67tgb.com/?p=624 最近项目结束,搞了一次代码分享.其中一位同学分享了一下自己在解决问题过程中的一些心得体会,感觉受益匪浅.整理出来,分享给大家. 建议使用自 ...

  7. (四)CSS选择器和派生选择器

    CSS派生选择器允许你根据文档的上下文关系来确定某个标签的样式.在学习派生之前,先来了解基本的CSS选择器.前面的文章中提到过下图,选择器的位置如下所示: CSS选择器 分为几种基本选择器:元素选择器 ...

  8. C#使用sharppcap实现网络抓包-----2

    虽然网上已经有了SharpSniffer 这一个SharpSniffer还是原创的无他,唯为学习工程文件下载:SharpSniffer.rar 1.创建套接字2.绑定到本机3.设置IOControl4 ...

  9. Nginx+Tomcat+Memcached 集群

    写过一篇 Apache Httpd+Tomcat 的集群, 现在来看看Nginx+Tomcat+Memcached是怎么集群的. 先看看用的版本和工具: Nginx: nginx-1.8.1 Tomc ...

  10. linux/unix网络编程之 poll

    转自http://www.cnblogs.com/zhuwbox/p/4222382.html poll 与 select 很类似,都是对描述符进行遍历,查看是否有描述符就绪.如果有就返回就绪文件描述 ...