Fetch More の例

Fetch More の例は、アイテムをアイテムビューモデルにオンデマンドで追加する方法を示しています。

大きな、あるいはおそらく無限のデータセットを持っている場合、アイテムを一括してモデルに追加する必要があります。

この例では、FileListModel - ディレクトリのエントリを含むアイテムビューモデル - を実装しています。また、Window 、GUIを設定し、モデルにディレクトリを供給します。

UIは、ルートディレクトリの内容を示すリストを持つダイアログで構成されています。ディレクトリはダブルクリックで移動できます。

一番下には、ビューがモデルにより多くのデータを要求したときのメッセージを表示するログウィンドウがあります。

これを使用するには、大きなディレクトリ(例えば、/bin )に移動し、一番下までスクロールします。取得されたデータを示すログメッセージが表示されます。

FileListModel のコードを見てみましょう。

FileListModel クラスの定義

FileListModelQAbstractListModel を継承し、ディレクトリの内容を格納します。ビューから要求されたときだけ、自分自身に項目を追加します。

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;
};

その秘密は、QAbstractItemModelfetchMore() と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 The Qt Company Ltd. 本書に含まれる文書の著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。