源码下载地址:https://gitee.com/Ailsc/Duilib
在duilib的实际应用过程中我们可能会遇见很大的数据量需要展示。此时如果我们使用传统的列表展示将会有如下问题:
1. ListItem 占用大量内存
2. 重绘将会产生大量的cpu消耗和卡顿
3. 排序和滚动导致卡死
所以此时我们就要使用一种新的技术支持:虚表。
思想分析主要分为两部分(10W数据为例):展示+滚动条
1. 由于展示空间的限制,所以我们最多可以展示数据量 max_item = 窗口高度/Item高度 + 1)
2. 因为数据量远远大于max_item,所以需要滚动条。滚动条范围:hrange = (10w/Item高度 - max_item)
3. 绘制,由于duilib样式的多样性,所以需要定制Item的样式和当前展示数据内容
实现接口:
//是否启用续表
void SetVirtual(bool bUse = false);
//设置续表的样式
void SetVirtualItemFormat(PULVirtualItemFormat vrtualitemfroamt);
//设置续表的数据量
void SetVirtualItemCount(int nCountItem)
//绘画续表的样式,当Item内容发生变更的时候发送消息,绘制数据内容
DUI_MSGTYPE_DRAWITEM:
wparam = 当前行数据控件 (CControlUI*)msg.wParam
lParam = 当前行数
具体实现代码:
//开启续表
virtual void InitWindow()
{
__super::InitWindow();
m_plist = static_cast<CListUI*>(m_PaintManager.FindControl(_T("list")));
///> 设置数据行为格式
m_plist->SetVirtual(true);
m_plist->SetVirtualItemFormat(CreateVirtualItem);
TCHAR szBuf[10] = _T("");
for (int i = 1;i <= ITEMCOUNT;++i)
{
sprintf_s(szBuf,_T("%06d"),i);
m_vdata.push_back(szBuf);
}
m_plist->SetVirtualItemCount(ITEMCOUNT);
}
//处理绘制消息
virtual void Notify(TNotifyUI& msg)
{
if(msg.sType == DUI_MSGTYPE_DRAWITEM)
{
DrawItem((CControlUI*)msg.wParam,msg.lParam);
}
__super::Notify(msg);
}
//根据行内容绘画续表
void DrawItem(CControlUI *pControl,int nRow)
{
CDuiString strFormat;
CListHBoxElementUI *pHBox = static_cast<CListHBoxElementUI*>(pControl-GetInterface(DUI_CTR_LISTHBOXELEMENT));
if(pHBox && nRow < ITEMCOUNT)
{
strFormat.Format(_T("%d"),nRow+1);
pHBox->GetItemAt(0)->SetText(strFormat);
pHBox->GetItemAt(1)->SetText(m_vdata[nRow]);
}
}
//指定虚表样式
CControlUI* CreateVirtualItem()
{
CListHBoxElementUI *pHBox = new CListHBoxElementUI;
//> 设置行高
pHBox->SetFixedHeight(28);
///> 位置
CCheckBoxUI *pCheckBox = new CCheckBoxUI;
pCheckBox->SetAttributeList(_T("selectedimage=\"file='skin\\res\\checked.png' dest='0,2,16,18'\" normalimage=\"file='skin\\res\\unchecked.png' dest='0,2,16,18'\""));
pCheckBox->SetFixedHeight(16);
pCheckBox->SetFixedWidth(30);
//> 名称
CLabelUI *pLabel = new CLabelUI;
///> 操作区域
CHorizontalLayoutUI *pHorizon = new CHorizontalLayoutUI;
CButtonUI *pButton = new CButtonUI;
pButton->SetAttributeList(_T("normalimage=\"file='skin\\res\\btn_normal.png'\" hotimage=\"file='skin\\res\\btn_hot.png'\" pushedimage=\"file='skin\\res\\btn_pushed.png'\""));
pButton->SetFixedHeight(16);
pButton->SetFixedWidth(30);
pButton->SetText(_T("编辑"));
CHorizontalLayoutUI *pAxis = new CHorizontalLayoutUI;
pAxis->SetFixedWidth(20);
CButtonUI *pButton2 = new CButtonUI;
pButton2->SetAttributeList(_T("normalimage=\"file='skin\\res\\btn_normal.png'\" hotimage=\"file='skin\\res\\btn_hot.png'\" pushedimage=\"file='skin\\res\\btn_pushed.png'\""));
pButton2->SetFixedHeight(16);
pButton2->SetFixedWidth(30);
pButton2->SetText(_T("删除"));
pHorizon->Add(pButton);
pHorizon->Add(pAxis);
pHorizon->Add(pButton2);
pHBox->Add(pCheckBox);
pHBox->Add(pLabel);
pHBox->Add(pHorizon);
return pHBox;
}
最终效果: