模型与视图:使用工作线程获取数据的列表模型
演示如何通过工作线程获取数据,从而实现具有响应式用户界面的列表模型。

本示例介绍了一个自定义项模型,该模型继承自QAbstractListModel 。该模型从位于单独QThread 中的工作线程对象获取数据,该线程从一个读取速度较慢的数据源中提取数据。
“多线程歌曲列表”示例概述
该数据源通过为每首从其获取的歌曲添加 100 毫秒的延迟,来模拟一个低效的数据源。这意味着加载完整的 3600 首歌曲列表将耗时 6 分钟,导致应用程序无法正常启动。 通过将QObject 放置在工作线程中,仅为视图的可见区域获取数据,从而缓解了这一延迟。
该工作线程对象对队列中持有的获取请求数量设有上限。这确保了仅获取歌曲列表当前可见部分的元素,从而避免了在用户已滚动浏览过列表部分内容后,仍需等待列表中不可见部分加载的情况。
本示例的重点在于视图的源模型。视图本身是一个未经过修改的、带有简单委托的 QMLListView 。线程的使用被隐藏在模型数据处理的实现中,ListView 无需进行任何自定义即可适配基于线程的模型。
此外,由于重点在于模型,因此将Qt Quick Controls 设置为在所有平台上均使用通用样式,以确保用户界面行为的一致性。
import QtQuick
import QtQuick.Controls.Universal工作原理
提供歌曲列表数据的业务逻辑被分离到DataStorage 类中,该类为模型提供了一个基于ID的简单接口。
QList<int> idList();
MediaElement item(int id) const;
std::optional<int> currentlyFetchedId() const;当模型向 DataStorage 请求数据时,存储器会首先检查是否已有可用数据。如果有,则会立即返回数据,这与非线程化模型的情况相同。如果未找到数据,DataStorage 会向 worker 对象发出一个dataFetchNeeded() 信号,并将一个空项添加到现有数据列表中。 添加该空项可确保不会针对同一列表项向工作者发送进一步的信号。
if (!m_items.contains(id)) {
m_items.insert(id, MediaElement{});
emit dataFetchNeeded(m_idList.indexOf(id));
}
return m_items.value(id);QueueWorker - 工作线程对象 - 通过向自身发送信号来处理收到的 dataFetchNeeded() 信号,这使得在开始耗时的数据读取操作之前,能够接收 QEventQueue 中已有的所有信号。
将该方法应用于动态模型
如果希望将该解决方案扩展到数据源(本例中为 RemoteMedia)中可能添加、移动或删除项的情况,则需要通过信号更新 DataStorage,使其与QAbstractItemModel::rowsMoved()、QAbstractItemModel::rowsInserted() 以及两个用于触发 ThreadedListModel 内部QAbstractItemModel::beginRemoveRows() 和QAbstractItemModel::endRemoveRows() 的信号相对应。
对于插入和移动操作,ThreadedListModel 只需调用QAbstractItemModel::beginInsertRows(),然后将新 ID 添加到其 ID 列表中,并调用QAbstractItemModel::endInsertRows()。 由于 ThreadedListModel 持有 ID 列表的副本,并且通过 ID 访问存储,因此无需从存储中发出开始和结束的信号。同样地,ThreadedListModel 可以调用QAbstractItemModel::beginMoveRows(),在其 ID 列表中移动 ID,然后调用QAbstractItemModel::endMoveRows()。
删除操作的情况稍显复杂。视图需要有机会在数据实际被删除之前请求获取即将被删除的数据。因此,DataStorage 需要发出删除警告,促使模型调用QAbstractItemModel::beginRemoveRows()。 在此阶段,ThreadedListModel 可能会收到一次或多次对data() 的调用。一旦对直接连接信号的调用在 DataStorage 端返回,DataStorage 即可移除该项,随后通过另一个信号再次通知模型,从而触发模型调用QAbstractItemModel::endRemoveRows()。
运行示例
您可以通过以下方式运行示例:
- Qt Creator
打开Welcome 模式,并从Examples 中选择该示例。有关更多信息,请参阅Qt Creator :教程:构建和运行。
- Qt Extension for Visual Studio Code
在Command Palette 中运行Qt: Open Qt examples 命令,并从列表中选择该示例。有关更多信息,请参阅Qt Extension for Visual Studio Code :教程:构建和运行。
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.