获取更多示例
Fetch More 示例展示了如何根据需要向项视图模型添加条目。
当您拥有大量(甚至可能是无限)数据集时,您需要批量地向模型中添加条目,并且最好只在条目被视图需要时(即,它们在视图中可见时)。
在这个例子中,我们实现了 FileListModel,这是一个包含目录条目的项视图模型。我们还有一个 Window,它设置 GUI 并向模型提供目录。
UI 由一个对话框组成,其中列出根目录的内容。可以通过双击来导航目录。
在底部,有一个日志窗口显示视图请求更多数据时的消息。
为了练习,导航到一个大目录(例如 /bin),然后滚动到顶部。将显示数据显示正在检索的消息。
让我们来探索 FileListModel 的代码。
FileListModel 类定义
FileListModel 继承自 QAbstractListModel,并包含目录的内容。它仅在视图要求时向自身添加条目。
class FileListModel : public QAbstractListModel { Q_OBJECT public: FileListModel(QObject *parent = nullptr); int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QFileInfo fileInfoAt(const QModelIndex &) const; signals: void numberPopulated(const QString &path, int start, int number, int total); public slots: void setDirPath(const QString &path); protected: bool canFetchMore(const QModelIndex &parent) const override; void fetchMore(const QModelIndex &parent) override; private: QFileInfoList fileList; QString path; QFileIconProvider iconProvider; int fileCount = 0; };
秘密在于对 QAbstractItemModel 中的 fetchMore() 和 canFetchMore() 的重新实现。这些函数在项视图需要更多条目时被调用。
setDirPath() 函数设置模型将工作的目录。每次我们向模型添加一批条目时,我们都发出 numberPopulated()。
我们将在 fileList 中保留所有的目录条目。fileCount 是已添加到模型中的项目数量。
FileListModel 类实现
我们首先检查 setDirPath()。
void FileListModel::setDirPath(const QString &path) { QDir dir(path); beginResetModel(); this->path = path; fileList = dir.entryInfoList(QDir::NoDot | QDir::AllEntries, QDir::Name); fileCount = 0; endResetModel(); }
我们使用 QDir 获取目录的内容。我们需要通知 QAbstractItemModel 我们想要从模型中移除所有项目(如果有的话)。
bool FileListModel::canFetchMore(const QModelIndex &parent) const { if (parent.isValid()) return false; return (fileCount < fileList.size()); }
canFetchMore() 函数在视图需要更多条目时被调用。如果还有我们尚未添加到模型中的条目,则返回 true;否则返回 false。
现在,fetchMore() 函数本身
void FileListModel::fetchMore(const QModelIndex &parent) { if (parent.isValid()) return; const int start = fileCount; const int remainder = int(fileList.size()) - start; const int itemsToFetch = qMin(batchSize, remainder); if (itemsToFetch <= 0) return; beginInsertRows(QModelIndex(), start, start + itemsToFetch - 1); fileCount += itemsToFetch; endInsertRows(); emit numberPopulated(path, start, itemsToFetch, int(fileList.size())); }
我们首先计算要获取的条目数。beginInsertRows() 和 endInsertRows() 对于 QAbstractItemModel 保持与行插入同步是强制性的。最后,我们发出 numberPopulated(),它被 Window 获取。
为了完成任务,我们还看看 rowCount() 和 data()。
int FileListModel::rowCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : fileCount; } QVariant FileListModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return {}; const int row = index.row(); if (row >= fileList.size() || row < 0) return {}; switch (role) { case Qt::DisplayRole: return fileList.at(row).fileName(); case Qt::BackgroundRole: { const int batch = row / batchSize; const QPalette &palette = QGuiApplication::palette(); return (batch % 2) != 0 ? palette.alternateBase() : palette.base(); } case Qt::DecorationRole: return iconProvider.icon(fileList.at(row)); } return {}; }
请注意,行数仅表示我们迄今为止已添加的项目数量,即不是目录中条目的数量。
在 data()
中,我们从 fileList
返回适当的条目。我们也使用不同的背景色来分隔批次。
© 2024 Qt公司有限公司。本文件中的文档贡献属于各自的版权所有者。本文件提供的文档根据自由软件开发基金会发布的 GNU自由文档许可第1.3版 条款进行许可。Qt及其相关标志是芬兰及其它全球国家的 Qt公司有限公司的商标。所有其他商标均为各自所有者的财产。