业务需求要求将数目200万左右的文件在qt的列表控件中显示,目前已经实现了个简单方案,时间仓促,先简单记录下实现思路。
从性能和使用的便利性来看,用支持Model/View(QTableView、QStandardItemModel之类)的控件是不二之选。另外还存在一些制约程序效率的瓶颈。在实际开发中,有相当多的优化技巧可以应用,在本方案中,笔者主要从两个方面下手来对程序的性能进行优化。
一、多线程
在方案中,笔者创建了一个继承于QObject的单例的(本质上是静态指针对象)Manager(一个抽象的“管理员”)对象,然后再创建一个相应QThread对象,并在程序运行时使用QThread的move to thread方法将Manager移入新线程并启动(Qt官方建议的创建新线程的方式,即以QThread对象作为“入口”)。最后需要使用信号槽让Manager和TableView对象得以联动。
查询数据的函数是Manager的函数,而Manager是在子线程中运行的,这样在查询的时候GUI就不会冻结,而且查询速度会更快些。
最终效果就是用户操作触发信号,随后子线程在查询后将通过信号将结果回馈,与此同时列表控件中的数据会被刷新。
二、动态性的局部加载
我们不需要一启动就一口气加载全部的数据,在方案中,笔者依据列表控件的尺寸和Item的尺寸从而动态地计算出需要展示给用户的item数量,首先先设置Model的行的总量,
// m_Model_FileItems 是成员函数,类型为自定义的QStandardItemModel
// 之所以自定义是因为需要完成一些MimeData功能
m_FileItemsModel->setRowCount(allCount);
其次,如果我们当前条目没有返回nullptr,即条目已经加载过了,便可以跳过不予加载以优化效率。
if (m_FileItemsModel->item(rowValue, 0) != nullptr)
{
std::cout << "条目已加载,跳过" << rowValue << endl;
}
else
{
...
}
然后我们可以根据目前的定位(根据列表侧边滑块的位置等数据计算得出列表控件范围内第一个到最后一个item的编号),将那些相应的item从数据库或容器中抓出来(数据按需从硬盘调到内存,在内存中进行操作以提高存取效率),通过Manager传递到View对象进行显示,因为每次顶多也就显示十多个条目,所以速度可以相当快。
至于最终的效率如何,需要看采用何种数据结构和算法。在本方案中,也仅仅是简单地使用Qt提供的链表进行查询就有相当不错的效率了。
以下是最终效果:
这些显示出来的条目都是在拖动进度条时临时加载的,状态栏中所显示的条目总数只是待加载的QStringList的总计数,而不是已加载的条目数。