このページでは

C

Qt Quick Ultraliteにおけるモデルとビュー

アプリケーションでは、データの提供や表示が必要になることがよくあります。Qt Quick では、データを表示するために「モデル」「ビュー」「デリゲート」という概念が用いられています。これらはデータの可視化をモジュール化することで、開発者やデザイナーがデータのさまざまな側面を制御できるようにします。 開発者は、データにほとんど変更を加えることなく、リストビューをグリッドビューに置き換えることができます。同様に、データのインスタンスをデリゲートにカプセル化することで、開発者はデータの表示方法や処理方法を指定できるようになります。

モデル、ビュー、デリゲートの関係を示す図。

  • モデル- データとその構造を保持します。モデルを作成する方法はいくつかあります。
  • ビュー- データを表示するコンテナです。ビューは、データをリスト形式やグリッド形式で表示することがあります。
  • デリゲート- データがビューにどのように表示されるかを決定します。デリゲートはモデル内の各データを取得してカプセル化します。データへのアクセスはデリゲートを介して行われます。また、デリゲートは編集可能なモデルにデータを書き戻すこともできます。

データを可視化するには、ビューのmodel プロパティをモデルにバインドし、delegate プロパティをコンポーネントまたは他の互換性のある型にバインドします。

ビューによるデータの表示

ビューは、項目のコレクションを格納するコンテナです。豊富な機能を備えており、スタイルや動作の要件に合わせてカスタマイズすることができます。

Qt Quick の基本的なグラフィカルタイプには、一連の標準ビューが用意されています:

  • Repeater - あらかじめ決められたレイアウトなしに、各データエントリごとにアイテムを作成する
  • ListView - 項目を水平または垂直のリストに配置する

これらのタイプには、それぞれ固有のプロパティや動作があります。詳細については、各タイプのドキュメントを参照してください。

ビューのデリゲート

ビューは、リスト内の項目を視覚的に表現するためにデリゲートを必要とします。ビューは、デリゲートによって定義されたテンプレートに従って、各項目リストを可視化します。モデル内の項目には、index プロパティおよび項目のプロパティを通じてアクセスできます。

Component {
    id: petdelegate
    Text {
        id: label
        width: view.width / petlist.count
        height: view.height / petlist.count
        font.pixelSize: 24
        text: if (index == 0)
            label.text = model.type + " (default)"
        else
            text: model.type
    }
}

デリゲートによってレンダリングされたテキスト項目を表示するListViewで、各項目にはモデルから取得したペットの種類が表示されます。

モデル

データは、名前付きデータロールを通じてデリゲートに提供され、デリゲートはこれらにバインドすることができます。以下は、typeageという2つのロールを持つListModel と、これらのロールにバインドしてその値を表示するデリゲートを持つListView の例です。

import QtQuick 2.15

Rectangle {
    color: "white"

    ListModel {
        id: myModel
        ListElement {
            type: "Dog"
            age: 8
        }
        ListElement {
            type: "Cat"
            age: 5
        }
    }

    Component {
        id: myDelegate
        Text {
            width: listView.width / myModel.count
            height: listView.height / myModel.count
            text: model.type + ", " + model.age
        }
    }

    ListView {
        id: listView
        anchors.fill: parent
        model: myModel
        delegate: myDelegate
    }
}

どのロールにアクセスできるかを制御し、デリゲートをより自己完結型にしてビューの外でも利用できるようにするには、必須プロパティを使用できます。 デリゲートに必須プロパティが含まれている場合、名前付きロールは提供されません。その代わりに、Qt Quick Ultraliteエンジンは、必須プロパティの名前がモデルのロール名と一致するかどうかを確認します。一致する場合、そのプロパティはモデルからの対応する値にバインドされます。

import QtQuick 2.15

Rectangle {
    color: "white"

    ListModel {
        id: myModel
        ListElement {
            type: "Dog"
            age: 8
            noise: "meow"
        }
        ListElement {
            type: "Cat"
            age: 5
            noise: "woof"
        }
    }

    Component {
        id: delegate
        Text {
            width: listView.width / myModel.count
            height: listView.height / myModel.count
            required property string type
            required property int age
            text: type + ", " + age
            // WRONG: text: type + ", " + noise
            // The above line would cause a compiler error
            // as there is no required property noise
        }
    }

    ListView {
        id: listView
        anchors.fill: parent
        model: myModel
        delegate: delegate
    }
}

モデルのプロパティとデリゲートのプロパティの間で命名上の競合がある場合、代わりに修飾されたモデル名を使用してロールにアクセスできます。 たとえば、Text 型に`type`プロパティと`age` プロパティがある場合、上記の例では、モデルからの`type`および`age`の値ではなく、これらのプロパティの値が表示されます。この場合、デリゲートがモデルからのプロパティ値を確実に表示するようにするには、代わりに `model.type ` および `model.age ` としてプロパティを参照すればよかったことになります。

また、デリゲートでは、モデル内の項目のインデックスを含む特別なインデックスロールも利用可能です。なお、項目がモデルから削除された場合、このインデックスは -1 に設定されることに注意してください。 インデックスロールにバインドする場合は、インデックスが -1 になる可能性、つまりそのアイテムがもはや有効ではない可能性をロジックで考慮するようにしてください。通常、そのアイテムはまもなく破棄されますが、一部のビューではデリゲートの破棄を遅延させることも可能です。

名前付きロールを持たないモデルでは、データはmodelDataロールを介して提供されます。modelDataロールは、ロールが 1 つしかないモデルにも提供されます。この場合、modelDataロールには、名前付きロールと同じデータが含まれます。

注: デリゲートに必須プロパティが含まれている場合、index およびmodelDataロールにはアクセスできません。ただし、デリゲート側に同じ名前の必須プロパティが存在する場合はこの限りではありません。

リストモデル

ListModel は、QMLで指定される単純な型の階層構造です。利用可能なロールは、ListElement プロパティによって指定されます。

ListModel {
    id: fruitModel

    ListElement {
        name: "Apple"
        cost: 245
    }
    ListElement {
        name: "Orange"
        cost: 325
    }
    ListElement {
        name: "Banana"
        cost: 195
    }
}

上記のモデルには、namecostの2つのロールがあります。これらは、ListView デリゲートによってバインドすることができます。例えば、次のようにします。

ListView {
    anchors.fill: parent
    model: fruitModel
    delegate: Row {
        width: parent.width / fruitModel.count
        height: parent.height / fruitModel.count
        Text { text: "Fruit: " + model.name }
        Text { text: " Cost: $" + model.cost }
    }
}

注: Qt Quickとは異なり ListModel およびListElement は読み取り専用です。つまり、このようなモデルに格納された値を変更することはできません。編集可能なモデルが必要な場合は、「Qul::ListModel 」および「C++コードとQMLの統合」を参照してください。

オブジェクトのリスト

オブジェクトリテラルを含む配列リテラルをモデルとして使用できます。配列の現在の要素は、modelData ロールとして利用可能であり、直接、またはmodel.modelData としてアクセスできます。

ListView {
    anchors.fill: parent
    model: [
        { name: "Apple", color: "green" },
        { name: "Pear", color: "pink" }
    ]
    delegate: Row {
        width: parent.width / 2
        height: parent.height / 2
        Text { text: "Fruit: " + modelData.name }
        Text { text: " Color: " + model.modelData.color }
    }
}

ListModel<T>型のプロパティ

ListModel<T> 型のプロパティをモデルとして使用できます。この場合、T のプロパティがモデルの構造を記述します。

これにより、モデルデータは外部から、あるいはState 内のPropertyChanges によって設定することが可能になります。

// MyView.qml
Item {
    width: 120
    height: 40

    property ListModel<NameAgeType> myModel

    ListView {
        anchors.fill: parents
        model: myModel
        delegate: Text {
            width: parent.width / myModel.count
            height: parent.height / myModel.count
            text: model.name
        }
    }
}
// NameAgeType.qml
QtObject {
    property string name
    property int age
}
// User.qml
Rectangle {
    Row {
        MyView {
            myModel: [{ name: "John Smith", age: 42 }]
        }
        MyView {
            myModel: ListModel { ListElement { name: "Smith"; age: 42 } }
        }
    }
}

注: ListModel<T> 型は Qt Quick Ultraliteに固有のものであり、Qt Quick には存在しません。これを使用すると、QMLコードはQt Quick と互換性がなくなります。これを使用しない場合、別のファイルでモデルを宣言することはできません。

モデルとしての整数

整数は、特定の数の型を含むモデルとして使用できます。この場合、モデルにはデータロールは存在しません。

次の例では、5つの要素を持つListView を作成しています:

Rectangle {

    Component {
        id: itemDelegate
        Text {
            width: listView.width / 5
            height: listView.height / 5
            text: "I am item number: " + index
        }
    }

    ListView {
        id: listView
        anchors.fill: parent
        model: 5
        delegate: itemDelegate
    }

}

注: 整数モデルに含まれる項目の数には、1億という上限があります。

C++ データモデル

モデルはC++で定義し、QMLから利用できるようにすることができます。この仕組みは、既存のC++データモデルや、変更可能なデータセット、あるいはその他の複雑なデータセットをQMLに公開する際に役立ちます。

詳細については、「Qul::ListModel 」および「C++コードとQMLの統合」をご覧ください。

特定の Qt ライセンスの下で利用可能です。
詳細はこちらをご覧ください。