概述
- 本文將介紹virtualListbox的用法。
- 更多請參考源碼。
一個樣式
樣式丑了點,勿噴。
重寫函數
使用virtualListbox, 需要一個派生類(繼承自基類VirtualListInterface)重寫父類的以下3個函數
class VirtualListInterface
{
public:
/**
* @brief 創建一個子項
* @return 返回創建后的子項指針
*/
virtual Control* CreateElement() = 0;
/**
* @brief 填充指定子項
* @param[in] control 子項控件指針
* @param[in] index 索引
* @return 返回創建后的子項指針
*/
virtual void FillElement(Control *control, int index) = 0;
/**
* @brief 獲取子項總數
* @return 返回子項總數
*/
virtual int GetElementtCount() = 0;
};
session_list類
- 自己定義了一個類,並繼承了VirtualListInterface類。
{
public:
explicit session_list(ui::VirtualListBox* pvlb) :plistbox_(pvlb) {}
session_list() {}
// 初始化參數
int init(ui::VirtualListBox* pvlb);
.......
}
- 重寫下面3個函數后,virtualListbox(它的數據代理類型VirtualListInterface類型)會自動調用下面的函數。
CreateElement 函數
- 如其名,負責創建一個list_item,我們可以定制自己item的樣式, 創建就需要寫在這里。
- 我的重寫如下:
ui::Control* session_list::CreateElement()
{
session_list_item* pitem = new(std::nothrow) session_list_item;
if (NULL == pitem)
return nullptr;
std::wstring session_item_xml(L"list_session/sersson_item.xml");
ui::GlobalManager::FillBoxWithCache(pitem, session_item_xml);
// 關聯item中的控件
pitem->init_controls_();
return pitem;
}
這里創建一個新的item, 其中sersson_item.xml,是item的自定義布局,后面貼其完整源碼
FillElement
它負責填充數據,比如,上面創建了item,item中的顯示內容可以放在這個函數實現。
void session_list::FillElement(ui::Control *control, int index)
{
if (nullptr == control || NULL == control || 0 > index)
return;
session_list_item* pitem = (session_list_item *)(control);
// 定制顯示數據
pitem->init_data_();
}
GetElementtCount
告訴當前有多少個item. 比如,100, 2000, 我這里設置的是20.
int session_list::GetElementtCount()
{
return 20;
}
還需要
上面僅僅是定制了item, 要顯示, 需要下面的函數配合使用才能達到效果
plistbox_->SetDataProvider(this);
plistbox_->SetElementHeight(50);
plistbox_->InitElement(20);
plistbox_->Refresh();
SetDataProvider
需要顯示指定其數據代理的對象。 我這里傳遞的是this, 是因為我自己定義的類是繼承的VirtualListInterface
SetElementHeight
設置子項高度, 示例中,使用DPI,額,我這里就先跳過。我這里設置的是50, 可以參考自己的session_item.xml中定義的height.
下面開始介紹item的個性化
ListContainerElement類
同樣的,需要自己新增一個類 繼承自ListContainerElement。 負責與界面控件的關聯就寫在這個派生類中,函數名可以自定義,下面的兩個函數非父類的函數。
class session_list_item :public ui::ListContainerElement
{
public:
// 關聯控件
virtual int init_controls_();
// 設置初始化數據
int init_data_();
private:
// 下面的控件用於與界面的控件綁定
// 頭像
ui::Label* label_protrait_ = nullptr;
// 姓名
ui::Label* label_name_ = nullptr;
// 最新消息
ui::RichEdit* rich_edit_last_msg_ = nullptr;
// 最新消息時間
ui::Label* label_last_msg_time_ = nullptr;
// 是否靜音
ui::Label* label_is_muted_ = nullptr;
};
init_controls_
我把初始化控件放在了這個函數中,當創建了item,再調用該函數完成控件綁定
int session_list_item::init_controls_()
{
auto find_sub_ctrl = [&](const std::wstring name, ui::Label* pdst)
{
ui::Control* ptmp = FindSubControl(name);
if (ptmp)
label_protrait_ = dynamic_cast<ui::Label*>(ptmp);
};
// 1.關聯其他label控件
find_sub_ctrl(L"label_portrait", label_protrait_);
find_sub_ctrl(L"label_name", label_name_);
find_sub_ctrl(L"label_last_msg_time", label_last_msg_time_);
find_sub_ctrl(L"label_is_muted", label_is_muted_);
// 2.關聯上一條消息控件
ui::Control* ptmp = FindSubControl(L"rich_edit_last_msg");
if (ptmp)
rich_edit_last_msg_ = dynamic_cast<ui::RichEdit*>(ptmp);
return 0;
}
init_data_
item顯示的內容的填充,可以放到這個函數中,FillElement函數中可以調用該函數完成數據綁定。
int session_list_item::init_data_()
{
//if (rich_edit_last_msg_)
// rich_edit_last_msg_->SetText(L"33");
auto set_text = [&](ui::Label*label, std::wstring str)
{
if (label)
label->SetText(str);
};
static int index = 0;
std::wstring str = fmt::format(L"{}", ++index);
set_text(label_protrait_, str);
//set_text(label_name_, L"22");
//set_text(label_last_msg_time_, L"33");
//set_text(label_is_muted_, L"44");
return 0;
}
session_item.xml
- 單獨維護item的樣式,很方便。 上面例子中的item樣式定義如下
- 整體采用水平布局。
- xml源碼內容
<?xml version="1.0" encoding="UTF-8"?>
<Window>
<ListContainerElement class="listitem" normalcolor="bk_wnd_lightcolor" height="60" margin="0,3,0,3">
<!--整體水平布局-->
<HBox width="stretch" height="stretch">
<!--頭像-->
<Label name="label_portrait" text="頭像" width="50" height="50" bkcolor="green" />
<!--中間顯示部分:姓名和上一條消息-->
<VBox width="stretch" height="stretch" bkcolor="red">
<!--姓名-->
<Label text="王老板" name="label_name" width="stretch"/>
<Control />
<!--上一條消息-->
<RichEdit text="這個月加班XXXXXXXXX" name="rich_edit_last_msg" multiline="false" vscrollbar="false" autovscroll="autovscroll" readonly="true" />
</VBox>
<!--右側顯示的事件和是否顯示提醒圖標-->
<VBox width="50" height="stretch" bkcolor="bk_listitem_selected" >
<!--上一條消息時間-->
<Label name="label_last_msg_time" text="08:08" />
<Control />
<!--是否顯示消息提醒圖標-->
<Label name="label_is_muted" text="靜音" />
</VBox>
</HBox>
<!--整體水平布局-->
</ListContainerElement>
</Window>
virtualListbox的xml
其定義不在上面的sesson_item.xml,如下,
<Box name="box_list_box" width="stretch" height="stretch">
<VirtualListBox class="list" name="virtual_list_box" vscrollunit="1" bkcolor="green" margin="10,0,0,0" vscrollbar="true" />
</Box>