nim_duilib之virtualListbox用法(22)

概述

  • 本文将介绍virtualListbox的用法。
  • 更多请参考源码。

一个样式

样式丑了点,勿喷。
nim_duilib之virtualListbox用法(22)

重写函数

使用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_ite,我们可以定制自己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样式定义如下
    nim_duilib之virtualListbox用法(22)
  • 整体采用水平布局。
  • 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>
上一篇:nim_duilib(4)之CheckBox


下一篇:正式发布DuiLib脚本系统 结合angelscript