本页内容

“获取更多”示例

“加载更多”示例演示了如何按需向项视图模型添加项。

一个用于获取项目并将更多项目添加到视图模型中的应用程序

当您处理大型(甚至可能是无限大)的数据集时,需要分批向视图模型中添加项目,并且最好仅在视图需要这些项目时(即项目在视图中可见时)才进行添加。

在此示例中,我们实现了FileListModel ——一个包含目录条目的项视图模型。我们还提供了Window ,该类负责设置图形用户界面(GUI)并将目录数据传入模型。

用户界面由一个对话框组成,其中包含一个显示根目录内容的列表。双击即可浏览目录。

底部有一个日志窗口,当视图向模型请求更多数据时会显示相关消息。

要测试该功能,请导航至一个大型目录(例如/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 中返回相应的条目。此外,我们还通过不同的背景颜色来区分各批次。

示例项目 @ code.qt.io

© 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.