モデルとビュー:データ取得にワーカースレッドを使用するリストモデル
データを取得するためにワーカースレッドを使用して、レスポンシブ UI でリストモデルを実装する方法を示します。
この例では、QAbstractListModel を継承したカスタムアイテムモデルを紹介します。このモデルは、別のQThread にあるワーカーオブジェクトからデータを取得し、低速なデータソースからデータを取得します。
スレッド化された曲リストの例の概要
データソースは、そこからフェッチされる曲ごとに100ミリ秒の遅延を追加することで、遅いデータソースをシミュレートしています。これは、3600 曲のリスト全体をロードするのに6 分かかることを意味し、アプリケーションを開くことが現実的ではなくなります。この遅延は、ワーカースレッドに配置されたQObject を使用して、ビューの可視領域のみデータをフェッチすることで軽減されます。
ワーカーオブジェクトは、キューに保持するフェッチ要求の数に制限があります。これにより、曲リストの現在表示されている部分の要素のみがフェッチされるようになり、ユーザーがすでにリストの一部をスクロールして通り過ぎてしまった場合に、リストの非表示部分の読み込みを待つ必要がなくなります。
この例の焦点はビューのソースモデルにあります。ビューそのものは、単純なデリゲートを持つQMLListView です。スレッドの使用はモデルデータ処理の実装の背後に隠されており、ListView はスレッドベースのモデルに適応できるようにカスタマイズする必要はありません。
また、モデルにフォーカスが当たっているため、Qt Quick Controlsは、すべてのプラットフォームでユニバーサルスタイルを使用するように設定されており、同一のUI動作を保証しています。
import QtQuick import QtQuick.Controls.Universal
どのように動作するか
曲リストのデータを提供するビジネスロジックは、DataStorage
クラスに分離され、モデルのためのシンプルなIDベースのインターフェースを提供します。
QList<int> idList(); MediaElement item(int id) const; std::optional<int> currentlyFetchedId() const;
モデルが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:Tutorialを参照してください:ビルドと実行。
© 2025 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.