モデルとビュー:データ取得にワーカースレッドを使用するリストモデル
ワーカースレッドを使用してデータを取得し、応答性の高い UI を備えたリストモデルを実装する方法を示します。

この例では、QAbstractListModel を継承したカスタムアイテムモデルを紹介します。このモデルは、別のQThread にあるワーカオブジェクトからデータを取得し、処理に時間がかかるデータソースからデータをフェッチします。
「スレッド化された曲リスト」例の概要
データソースは、取得する曲ごとに 100 ミリ秒の遅延を加えることで、処理の遅いデータソースをシミュレートしています。つまり、3600 曲のリスト全体を読み込むには 6 分を要することになり、アプリケーションの起動が現実的ではなくなってしまいます。 この遅延は、ワーカースレッドに配置されたQObject を使用して、ビューの可視領域のデータのみを取得することで軽減されます。
ワーカーオブジェクトには、キューに保持できるフェッチリクエストの数に制限があります。これにより、ユーザーがリストの一部をスクロールして通り過ぎた場合でも、リストの現在表示されている部分の要素のみがフェッチされ、リストの非表示部分の読み込みを待つ必要がなくなります。
この例の焦点は、ビューのソースモデルにあります。ビュー自体は、単純なデリゲートを備えた、変更を加えていない QMLListView です。スレッドの使用はモデルデータ処理の実装の背後で隠されており、ListView は、スレッドベースのモデルに適応するためにいかなるカスタマイズも必要としません。
また、モデルに重点を置いているため、Qt Quick のコントロールは、すべてのプラットフォームで「ユニバーサル」スタイルを使用するように設定されており、これにより一貫したUI動作が保証されます。
import QtQuick
import QtQuick.Controls.Universal仕組み
曲リストデータを提供するビジネスロジックは、モデルに対してシンプルなIDベースのインターフェースを提供するDataStorage クラスに分離されています。
QList<int> idList();
MediaElement item(int id) const;
std::optional<int> currentlyFetchedId() const;モデルが DataStorage にデータを要求すると、DataStorage はまずそのデータがすでに利用可能かどうかを確認します。利用可能な場合、スレッドを使用しないモデルと同様に、データは即座に返されます。データが見つからない場合、DataStorage は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() をトリガーする 2 つのシグナルを追加する必要があります。
挿入および移動については、ThreadedListModelは単にQAbstractItemModel::beginInsertRows()を呼び出し、そのIDリストに新しいIDを追加してから、QAbstractItemModel::endInsertRows()を呼び出せばよい。 ThreadedListModel は ID リストのコピーを保持し、ID によってストレージにアクセスするため、ストレージ側から開始位置や終了位置を通知する必要はありません。同様に、ThreadedListModel はQAbstractItemModel::beginMoveRows() を呼び出し、ID リスト内の ID を移動させた後、QAbstractItemModel::endMoveRows() を呼び出すことができます。
削除の場合は、やや複雑になります。ビュー側では、データが実際に削除される前に、削除対象のデータを要求できる必要があります。そのため、DataStorageは削除の警告を送信し、ModelにQAbstractItemModel::beginRemoveRows()を呼び出させる必要があります。 この段階では、ThreadedListModel に対して 1 回以上の `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.