获取更多示例

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 返回适当的条目。我们也使用不同的背景色来分隔批次。

示例项目 @ code.qt.io

© 2024 Qt公司有限公司。本文件中的文档贡献属于各自的版权所有者。本文件提供的文档根据自由软件开发基金会发布的 GNU自由文档许可第1.3版 条款进行许可。Qt及其相关标志是芬兰及其它全球国家的 Qt公司有限公司的商标。所有其他商标均为各自所有者的财产。