关于duilib中的list的扩展探索

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

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

 

先看一下实现的效果:

 

 

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

1. 表头支持控件

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

 

[cpp] view
plain
copy

  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函数,在此函数中,重新校正数据列宽与表头宽度一致,具体如下:

[cpp] view
plain
copy

  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.    
  23. CListHeaderItemUI *pHeaderItem = static_cast<CListHeaderItemUI*>(m_pHeader->GetItemAt(i));  
  24. if (pHorizontalLayout != NULL && pHeaderItem != NULL)  
  25. {  
  26. RECT rtHeader = pHeaderItem->GetPos();  
  27. RECT rt = pHorizontalLayout->GetPos();  
  28. rt.left = rtHeader.left;  
  29. rt.right = rtHeader.right;  
  30. pHorizontalLayout->SetPos(rt);  
  31. }  
  32. }  
  33.     }  
  34. 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文件,将行数据添加到列表中:

[cpp] view
plain
copy

  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). 以下代码用于动态的添加列:

[cpp] view
plain
copy

  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.    
  16. delete pHeaderItem;  
  17. pHeaderItem = NULL;  
  18. return FALSE;  
  19. }  
  20.    
  21. BOOL CListUIEx::SetHeaderItemData(int nColumn, CControlUI* pControl)  
  22. {  
  23. CListHeaderUI *pHeader = CListUI::GetHeader();  
  24. if (pHeader == NULL)  
  25. {  
  26. return FALSE;  
  27. }  
  28. CListHeaderItemUI *pHeaderItem = (CListHeaderItemUI *)pHeader->GetItemAt(nColumn);  
  29. pHeaderItem->Add(pControl);  
  30. }  

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

[cpp] view
plain
copy

  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.    
  12. CCheckBoxUI *pBtnUI = new CCheckBoxUI;  
  13. pBtnUI->SetText("选择");  
  14. pBtnUI->SetAttribute(_T("selectedimage"), _T("file='checkbox_p.png' dest='0,2,15,17'"));  
  15. pBtnUI->SetAttribute(_T("normalimage"), _T("file='checkbox_h.png' dest='0,2,15,17'"));  
  16. pBtnUI->SetAttribute(_T("textpadding"), _T("20,3,0,0"));  
  17. pBtnUI->SetAttribute(_T("align"), _T("right"));  
  18. pBtnUI->SetFloat(true);  
  19. pBtnUI->SetAttribute("pos", "20,3, 65, 20");  
  20.    
  21. pList->SetHeaderItemData(3, pBtnUI);  

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

[cpp] view
plain
copy

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

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

[cpp] view
plain
copy

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

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

 

 

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

  

后记:

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

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

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

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

时间: 2024-10-02 08:49:52

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

php 5.6版本中编写一个PHP扩展的简单示例

 这篇文章主要介绍了php 5.6版本中编写一个PHP扩展的简单示例,本文给出扩展实现代码.编译方法.配置方法和使用例子等内容,需要的朋友可以参考下     有时候在php本身没有满足需求的api时候,需要自己写相应的扩展,扩展写完之后进行编译,即可加入自己的开发环境中,扩展php的功能. 这里实现一个连接字符串和int型数的连接操作的简单扩展. 首先,下载最新的php源码安装包,进入ext/目录,新建extstrcat.def: 代码如下: string extstrcat(string st

windows-Windows CE 6.0中,怎么模拟输入扩展字符?比如英镑/法郎的符号

问题描述 Windows CE 6.0中,怎么模拟输入扩展字符?比如英镑/法郎的符号 keybd_event所用的虚拟键码里没有ASCII中的扩展字符. 那么请问Windows CE 6.0中,怎么模拟输入扩展字符? 扩展字符如下:

Laravel4中的Validator验证扩展用法详解_php实例

本文实例讲述了Laravel4中的Validator验证扩展用法.分享给大家供大家参考,具体如下: 不管写接口还是写web页面,实质都是传入参数,然后进行业务逻辑,然后再输出具体内容.所以,对参数的验证是不可避免的一个环节,比如传过来的email是不是为空,是不是合法的email格式?laravel已经为phper想到简化这种逻辑的办法了.就是Validator. Validator的使用 制造一个验证器 validator使用Validator::make可以制造一个验证器.然后使用验证器判断

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

                                           C++中extern "C"含义深层探索                                                        1.引言   C++语言的创建初衷是"a better C",但是这并不意味着C++中类似C语言的全局变量和函数所采用的编译和连接方式与C语言完全相同.作为一种欲与C兼容的语言,C++保留了一部分过程式语言的特点(被世人称为&quo

LibreOffice 中的六大实用扩展组件

LibreOffice 中的六大实用扩展组件 图片来源:Opensource.com LibreOffice 是最好的自由办公套件,并在所有的主要 Linux 发行版中得到应用.尽管 LibreOffice 已经拥有了大多数特性,它仍然可以通过添加一种叫做扩展extension的特定的附加组件来增加功能. LibreOffice 的扩展组件的网站是 extensions.libreoffice.org.扩展组件只是一些工具,可以在安装主体上进行独立添加或者移除,以便增加新功能或者让已有功能更容易

duilib win32 c++-duilib中HandleMessage()与HandleCustomerMessage()

问题描述 duilib中HandleMessage()与HandleCustomerMessage() duilib中HandleMessage()与HandleCustomerMessage()区别 以及他们与Messagehandle的关联 解决方案 一个窗口被创建,它会有一个消息循环处理模块,比如: while( GetMessage(&Msg, NULL, 0, 0)) { TranslateMessage( &Msg) ; DispatchMessage( &Msg) ;

Laravel中基于Artisan View扩展包创建及删除应用视图文件的方法

本文实例讲述了Laravel中基于Artisan View扩展包创建及删除应用视图文件的方法.分享给大家供大家参考,具体如下: 1.简介 本扩展包添加了两个视图相关的Artisan命令到Laravel应用,以便我们通过Artisan命令即可创建和管理视图文件,可谓是进一步解放了生产力. 2.安装 还是通过Composer安装: composer require sven/artisan-view 安装完成后到config/app.php中注册服务提供者ArtisanViewServiceProv

Laravel4中的Validator验证扩展用法详解

本文实例讲述了Laravel4中的Validator验证扩展用法.分享给大家供大家参考,具体如下: 不管写接口还是写web页面,实质都是传入参数,然后进行业务逻辑,然后再输出具体内容.所以,对参数的验证是不可避免的一个环节,比如传过来的email是不是为空,是不是合法的email格式?laravel已经为phper想到简化这种逻辑的办法了.就是Validator. Validator的使用 制造一个验证器 validator使用Validator::make可以制造一个验证器.然后使用验证器判断

语音合成在语音助手中的应用及扩展

语音合成作为人机交互中必不可少的一个环节,随着计算机的运算和存储能力的迅猛发展,语音合成技术由早期的基于规则的参数合成,到基于小样本的拼接调整合成,并逐渐发展为现在比较流行的基于大语料库的拼接合成.与此同时,合成语音的自然度和音质都得到了明显的改善,在一定程度上达到了人们的应用需求,从而促进了其在实际系统中的应用.目前,语音合成技术已经在自动应答呼叫中心(包括金融.电信和政府等).电话信息查询(包括天气.交通和旅游等).汽车导航以及电子邮件阅读等方面得到广泛的应用,同时针对娱乐和教育方面的应用也