QMLモデルの異種階層

はじめに



多くの場合、モデルを次のように構成する必要があります。1つの構造を持つモデルの同じレベルで、別のレベルでモデルの構造が変更されます。 たとえば、デバイスのリストを表示し、各デバイスに設定グループがあり、各設定グループにさまざまなタイプの設定のリストがあるタスクを考えます。 簡単にするために、デバイスには名前とグループのリストのみがあると仮定します。 グループには、名前と設定のリストのみがあります。 設定には、名前とタイプ(チェックボックス、テキストボックス、またはスライダー)のみがあります。







このパターンは、 記事に基づいて体系化されました。 以下は、GoFに似たパターンの説明です。



予定



QMLを使用したC ++での複雑なモデルの使用を構造化するパターン。 ネストされたモデルリストの使用を促進して、階層構造を形成します。 同時に、QMLで使用する場合、複雑さは増加しません。



適用性



次の場合にパターンを使用します。





構造







会員





関係



リストオブジェクトは、コンストラクターでプロトタイプとして指定されたリストアイテムのクラスにロールデータを委任します。 サブモデルを持つ要素から、または単純なリストアイテムから継承する必要があります。 QMLでは、子モデルにアクセスするには、subModelFromIdメソッドを呼び出す必要があります。ここで、パラメーターは現在の要素のidロールです。



C ++コード例



デバイスモデルを追加します。



class DeviceModelItem : public Models::SubListedListItem { Q_OBJECT public: enum GroupModelItemRoles { deviceId = Qt::UserRole + 1, deviceNameRole }; DeviceModelItem(QObject* parent = 0); int id() const; QVariant data(int role) const; QHash<int, QByteArray> roleNames() const; Models::ListModel* submodel() const; private: int _id; static int g_id; QString deviceName; Models::ListModel* groupListModel; };
      
      





識別子を追跡するには、グローバルカウンターg_idを使用します。現在のデバイスの識別子は_idです。 コンストラクターで、サブモデルを追加し、名前を初期化します。



 DeviceModelItem::DeviceModelItem(QObject *parent):SubListedListItem(parent), _id(g_id++) { deviceName = QString("Device %1").arg(_id); groupListModel = new Models::SubListedListModel(new GroupModelItem()); //     groupListModel->appendRow(new GroupModelItem()); groupListModel->appendRow(new GroupModelItem()); }
      
      





ロール処理:



 QVariant DeviceModelItem::data(int role) const { switch (role) { case deviceId: return this->id(); case deviceNameRole: return this->deviceName; default: return QVariant(); } } QHash<int, QByteArray> DeviceModelItem::roleNames() const { QHash<int, QByteArray> roles; roles[deviceId] = "deviceId"; roles[deviceNameRole] = "deviceName"; return roles; }
      
      





グループのモデルは似ていますが、コンストラクターでサブモデルのないリストを作成する点が異なります。



 GroupModelItem::GroupModelItem(QObject *parent):SubListedListItem(parent), _id(g_id++) { groupName = QString("Group %1").arg(_id); settingsListModel = new Models::ListModel(new SettingsModelItem()); ... }
      
      





モデルでは、設定はすでにListItemから継承されています。



 class SettingsModelItem : public Models::ListItem { Q_OBJECT public: enum SettingsModelItemRoles { settingsId = Qt::UserRole + 1, settingsNameRole, settingsTypeRole } ... }
      
      





設定にサブモデルは必要ありません。 次に、ルートデバイスモデルをコンテキストに追加します。



 int main(int argc, char *argv[]) { //     touch QGuiApplication app(argc, argv); QQmlApplicationEngine engine; Models::ListModel* devicesModel = new Models::SubListedListModel(new DeviceModelItem()); //DEBUG devicesModel->appendRow(new DeviceModelItem()); devicesModel->appendRow(new DeviceModelItem()); devicesModel->appendRow(new DeviceModelItem()); devicesModel->appendRow(new DeviceModelItem()); devicesModel->appendRow(new DeviceModelItem()); engine.rootContext()->setContextProperty("deviceModel",devicesModel); ... }
      
      





QMLサンプルコード



ナビゲーションモデルとして、StackView(main.qml)を使用します。



 StackView { id: stackView anchors.fill: parent initialItem: Item { width: parent.width height: parent.height ListView { model: deviceModel anchors.fill: parent delegate: AndroidDelegate { text: deviceName onClicked: stackView.push({item:Qt.resolvedUrl("pages/GroupPage.qml"), properties:{subModel:deviceModel.subModelFromId(model.deviceId)}}) } } } }
      
      





グループページの場合、subModelFromIdを介してサブモデルがインストールされました。 グループモデルでは、同じ方法で処理します。



 ScrollView { ... property variant subModel: null ListView { ... model: subModel delegate: AndroidDelegate { text: groupName onClicked: stackView.push({item:Qt.resolvedUrl("SettingsPage.qml"), properties:{subModel:subModel.subModelFromId(model.groupId)}}) } } ... }
      
      





設定ページのみのリストの場合:



 ListView { id: settingsView ... model: subModel delegate: Item { CheckBox{ visible: settingsType == 0 ... } Column{ ... visible: settingsType == 1 Text{text: settingsName} TextField {text: "Text input"} } Column{ ... visible: settingsType == 2 Text{text: settingsName} Slider {value: 1.0} } }
      
      





結果のスクリーンショット







ソースへのリンク: GitHub

ソース記事へのリンク: 記事



All Articles