QMLの基礎 - モデルとビュー

2021年10月19日 (火) 16:19時点におけるWiki (トーク | 投稿記録)による版 (ページの作成:「== 概要 == ソフトウェアはデータを生成して、データを表示する必要がある。<br> Qt Quickには、データを表示するためのモデル、…」)
(差分) ← 古い版 | 最新版 (差分) | 新しい版 → (差分)

概要

ソフトウェアはデータを生成して、データを表示する必要がある。
Qt Quickには、データを表示するためのモデル、ビュー、デリゲートという概念が存在する。

モデル、ビュー、デリゲートは、データの可視化をモジュール化し、開発者がデータの様々な側面をコントロールできる。
また、データにほとんど変更を加えることなく、リストビューとグリッドビューを入れ替えることができる。
同様に、データのインスタンスをデリゲートにカプセル化することで、データの表示方法や処理方法を決定することができる。

  • モデル
    データとその構造を含む。
    モデルを作成するためのQMLタイプがいくつかある。

  • ビュー
    データを表示するコンテナである。
    ビューは、リストやグリッドでデータを表示する。

  • デリゲート
    データがビューにどのように表示されるかを指定する。
    デリゲートはモデルの各データを受け取り、それをカプセル化する。データはデリゲートを通してアクセスできる。
    デリゲートは、データを編集可能なモデルに書き戻すこともできる。(例. TextFieldonAcceptedハンドラ内)
    データを可視化するには、ビューのmodelプロパティをモデル、delegateプロパティをコンポーネントやその他の互換性のあるタイプにバインドする。




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

ビューは、アイテムのコレクションのためのコンテナである。
豊富な機能を持ち、スタイルや動作の要求に合わせてカスタマイズすることができる。

Qt Quickの基本セットには、以下に示す標準的なビューが用意されている。

  • ListView
    水平または垂直のリストにアイテムを配置する。

  • GridView
    利用可能なスペース内のグリッドにアイテムを配置する。

  • PathView
    アイテムをパス上に配置する。


上記のビューには、それぞれ専用のプロパティと動作がある。


ビューの装飾

ビューでは、headerfootersection等の装飾用プロパティを使用して、見た目をカスタマイズすることができる。

これらのプロパティに対して、オブジェクト(通常は別のビジュアルオブジェクト)をバインドすることにより、ビューを装飾することができる。
footerには、ボーダーを表示するRectangleアイテムや、ビューの上にロゴを表示するヘッダ等がある。

以下の例では、あるクラブがメンバーリストを自社のブランドカラーで装飾している。
メンバーリストはモデルの中にあり、デリゲートはモデルのコンテンツを表示している。

クラブは、ビジュアルアイテムをheaderプロパティとfooterプロパティにバインドすることにより、メンバーリストを装飾することができる。
ビジュアルアイテムは、同一ファイル、他のファイル、Componentアイテムで定義することができる。

 ListModel {
    id: nameModel
    ListElement { name: "Alice" }
    ListElement { name: "Bob" }
    ListElement { name: "Jane" }
    ListElement { name: "Harry" }
    ListElement { name: "Wendy" }
 }
 
 Component {
    id: nameDelegate
    Text {
       text: name;
       font.pixelSize: 24
    }
 }
 
 ListView {
    anchors.fill: parent
    clip: true
 
    model: nameModel
    delegate: nameDelegate
 
    header: bannercomponent
 
    footer: Rectangle {
       width: parent.width
       height: 30;
       gradient: clubcolors
    }
 
    highlight: Rectangle {
        width: parent.width
        color: "lightgray"
    }
 }
 
 Component {  // instantiated when header is processed
    id: bannercomponent
    Rectangle {
       id: banner
       width: parent.width
       height: 50
       gradient: clubcolors
 
       border {
          color: "#9EDDF2"
          width: 2
       }
 
       Text {
          anchors.centerIn: parent
          text: "Club Members"
          font.pixelSize: 32
       }
    }
 }
 
 Gradient {
    id: clubcolors
 
    GradientStop {
       position: 0.0
       color: "#8EE2FE"
    }
 
    GradientStop {
       position: 0.66
       color: "#7ED2EE"
    }
 }




マウスとタッチの操作

ビューは、コンテンツのドラッグやフリックを処理するが、個々のデリゲートとのタッチ操作は処理しない。

デリゲートがタッチ入力に反応してcurrentIndexプロパティを設定するためには、適切なタッチ処理を持つMouseAreaアイテムをデリゲートに定義する必要がある。

※注意
highlightRangeModeプロパティがStrictlyEnforceRangeに設定されている場合、ビューは常にcurrentIndexプロパティが指定されたハイライト範囲内にあることを保証するため、
currentIndexプロパティはビューをドラッグおよびフリックしても影響を受けない。


ListViewのセクション

ListViewのコンテンツはセクションにグループ化されるため、関連するリストアイテムは、そのセクションに応じてラベル付けされる。
また、セクションは、デリゲートを使用して装飾することもできる。

以下の例では、ListViewに、人名とチームの所属を示すリストを作成している。

ListViewには、隣接するアイテムや関連するアイテムをセクションにまとめることができるpropertyプロパティが存在する。
propertyプロパティは、どのリストタイプのプロパティをセクションとして使用するかを決定する。

cliteriaプロパティは、セクション名の表示方法を決定する。
delegateプロパティは、ListView等のdelegateプロパティと同様である。

 ListModel {
    id: nameModel
    ListElement { name: "Alice"; team: "Crypto" }
    ListElement { name: "Bob"; team: "Crypto" }
    ListElement { name: "Jane"; team: "QA" }
    ListElement { name: "Victor"; team: "QA" }
    ListElement { name: "Wendy"; team: "Graphics" }
 }
 
 Component {
    id: nameDelegate
    Text {
       text: name;
       font.pixelSize: 24
       anchors.left: parent.left
       anchors.leftMargin: 2
    }
 }
 
 ListView {
    anchors.fill: parent
    model: nameModel
    delegate: nameDelegate
    focus: true
 
    highlight: Rectangle {
       color: "lightblue"
       width: parent.width
    }
 
    section {
       property: "team"
       criteria: ViewSection.FullString
       delegate: Rectangle {
          color: "#b0dfb0"
          width: parent.width
          height: childrenRect.height + 4
          Text {
             anchors.horizontalCenter: parent.horizontalCenter
             font.pixelSize: 16
             font.bold: true
             text: section
          }
       }
    }
 }