MochiuWiki : SUSE, EC, PCB
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
QMLの基礎 - モデルとビューのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
QMLの基礎 - モデルとビュー
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == ソフトウェアはデータを生成して、データを表示する必要がある。<br> Qt Quickには、データを表示するためのモデル、ビュー、デリゲートという概念が存在する。<br> <br> モデル、ビュー、デリゲートは、データの可視化をモジュール化し、開発者がデータの様々な側面をコントロールできる。<br> また、データにほとんど変更を加えることなく、リストビューとグリッドビューを入れ替えることができる。<br> 同様に、データのインスタンスをデリゲートにカプセル化することで、データの表示方法や処理方法を決定することができる。<br> <br> * モデル *: データとその構造を含む。 *: モデルを作成するためのQMLタイプがいくつかある。 *: <br> * ビュー *: データを表示するコンテナである。 *: ビューは、リストやグリッドでデータを表示する。 *: <br> * デリゲート *: データがビューにどのように表示されるかを指定する。 *: デリゲートはモデルの各データを受け取り、それをカプセル化する。データはデリゲートを通してアクセスできる。 *: デリゲートは、データを編集可能なモデルに書き戻すこともできる。(例. <code>TextField</code>の<code>onAccepted</code>ハンドラ内) *: データを可視化するには、ビューの<code>model</code>プロパティをモデル、<code>delegate</code>プロパティをコンポーネントやその他の互換性のあるタイプにバインドする。 <br> [[ファイル:QML Model and View 1.png|フレームなし|中央]] <br><br> == ビューによるデータの表示 == ビューは、アイテムのコレクションのためのコンテナである。<br> 豊富な機能を持ち、スタイルや動作の要求に合わせてカスタマイズすることができる。<br> <br> Qt Quickの基本セットには、以下に示す標準的なビューが用意されている。<br> * ListView *: 水平または垂直のリストにアイテムを配置する。 *: <br> * GridView *: 利用可能なスペース内のグリッドにアイテムを配置する。 *: <br> * PathView *: アイテムをパス上に配置する。 <br> 上記のビューには、それぞれ専用のプロパティと動作がある。<br> <br> ==== ビューの装飾 ==== ビューでは、<code>header</code>、<code>footer</code>、<code>section</code>等の装飾用プロパティを使用して、見た目をカスタマイズすることができる。<br> <br> これらのプロパティに対して、オブジェクト(通常は別のビジュアルオブジェクト)をバインドすることにより、ビューを装飾することができる。<br> footerには、ボーダーを表示するRectangleアイテムや、ビューの上にロゴを表示するヘッダ等がある。<br> <br> 以下の例では、あるクラブがメンバーリストを自社のブランドカラーで装飾している。<br> メンバーリストはモデルの中にあり、デリゲートはモデルのコンテンツを表示している。<br> <br> クラブは、ビジュアルアイテムを<code>header</code>プロパティと<code>footer</code>プロパティにバインドすることにより、メンバーリストを装飾することができる。<br> ビジュアルアイテムは、同一ファイル、他のファイル、<code>Component</code>アイテムで定義することができる。<br> <syntaxhighlight lang="qml"> 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" } } </syntaxhighlight> <br> [[ファイル:QML Model and View 2.png|フレームなし|中央]] <br> ==== マウスとタッチの操作 ==== ビューは、コンテンツのドラッグやフリックを処理するが、個々のデリゲートとのタッチ操作は処理しない。<br> <br> デリゲートがタッチ入力に反応して<code>currentIndex</code>プロパティを設定するためには、適切なタッチ処理を持つ<code>MouseArea</code>アイテムをデリゲートに定義する必要がある。<br> <br> <u>※注意</u><br> <u><code>highlightRangeMode</code>プロパティが<code>StrictlyEnforceRange</code>に設定されている場合、ビューは常に<code>currentIndex</code>プロパティが指定されたハイライト範囲内にあることを保証するため、</u><br> <u><code>currentIndex</code>プロパティはビューをドラッグおよびフリックしても影響を受けない。</u><br> <br> ==== ListViewのセクション ==== <code>ListView</code>のコンテンツはセクションにグループ化されるため、関連するリストアイテムは、そのセクションに応じてラベル付けされる。<br> また、セクションは、デリゲートを使用して装飾することもできる。<br> <br> 以下の例では、<code>ListView</code>に、人名とチームの所属を示すリストを作成している。<br> <br> <code>ListView</code>には、隣接するアイテムや関連するアイテムをセクションにまとめることができる<code>property</code>プロパティが存在する。<br> <code>property</code>プロパティは、どのリストタイプのプロパティをセクションとして使用するかを決定する。<br> <br> <code>cliteria</code>プロパティは、セクション名の表示方法を決定する。<br> <code>delegate</code>プロパティは、<code>ListView</code>等の<code>delegate</code>プロパティと同様である。<br> <syntaxhighlight lang="qml"> 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 } } } } </syntaxhighlight> <br> [[ファイル:QML Model and View 3.png|フレームなし|中央]] <br><br> == ビューのデリゲート == ビューは、リストの中のアイテムを視覚的に表現するために、デリゲートが必要となる。<br> <br> ビューは、デリゲートにより定義されたテンプレートにしたがって、各アイテムのリストを生成する。<br> モデル内のアイテムは、アイテムのプロパティだけでなく、インデックスのプロパティにもアクセスできる。<br> [[ファイル:QML Model and View 4.png|フレームなし|中央]] <br> <syntaxhighlight lang="qml"> Component { // delegate: <アイテム名> { を使用することもできる id: petdelegate Text { id: label font.pixelSize: 24 text: index === 0 ? type + " (default)" : type required property int index required property string type } } </syntaxhighlight> <br> <br> ==== デリゲートからのビューやモデルへのアクセス ==== デリゲートがバインドされているビューは、<code>view</code>プロパティを介してデリゲートからアクセスできる。(例. <code>ListView.view</code>, <code>GridView.view</code>等)<br> したがって、対応するモデルとそのプロパティは、<code>view.model</code>を通じて使用できる。(例. <code>ListView.view.model</code>, <code>GridView.view.model</code>等)<br> <br> さらに、モデルに定義されているシグナルやメソッドもアクセス可能である。<br> 例えば、複数のビューに同じデリゲートを使用したいが、装飾等の機能は各ビューごとに異なるものにする場合や他の異なる設定を各ビューのプロパティにする場合に活用できる。<br> 同様に、モデルの各プロパティにアクセスおよび表示することもできる。<br> <br> 以下の例では、デリゲート内の1つのTextアイテムは、<code>ListModel</code>内のlanguageプロパティを表示している。<br> また、デリゲート内の1つのTextアイテムの色は、<code>ListView</code>内のfruit_colorプロパティに依存している。<br> <syntaxhighlight lang="qml"> Rectangle { width: 200 height: 200 ListView { model: fruitModel delegate: fruitDelegate anchors.fill: parent property color fruit_color: "green" } ListModel { id: fruitModel property string language: "en" ListElement { name: "Apple" cost: 2.45 } ListElement { name: "Orange" cost: 3.25 } ListElement { name: "Banana" cost: 1.95 } } Component { id: fruitDelegate Row { id: fruit Text { text: " Fruit: " + name color: fruit.ListView.view.fruit_color } Text { text: " Cost: $" + cost } Text { text: " Language: " + fruit.ListView.view.model.language } } } } </syntaxhighlight> <br><br> == モデル == データは、デリゲートがバインドすることができる名前付きのデータロールを介してデリゲートに提供される。<br> <br> 以下の例では、typeとageという2つのロールを持つListModel、および、これらのロールにバインドして値を表示するデリゲートを持つListViewを作成している。<br> <syntaxhighlight lang="qml"> import QtQuick 2.15 Item { width: 200 height: 250 ListModel { id: myModel ListElement { type: "Dog" age: 8 } ListElement { type: "Cat" age: 5 } } Component { id: myDelegate Text { text: type + ", " + age } } ListView { anchors.fill: parent model: myModel delegate: myDelegate } } </syntaxhighlight> <br> ロールのアクセスをより細かく制御する場合、および、デリゲートをビュー外部で使用する場合は、以下のように記述する。<br> <syntaxhighlight lang="qml"> required property <データ型> <プロパティ名> </syntaxhighlight> <br> デリゲートに必須プロパティが含まれている場合、名前付きのロールは提供されない。<br> 代わりに、QMLエンジンは、まず、必須プロパティ名がモデルロールの名前と一致するかどうかをチェックして、一致する場合、その必須プロパティはモデルの対応する値にバインドされる。<br> <syntaxhighlight lang="qml"> import QtQuick 2.15 Item { width: 200 height: 250 ListModel { id: myModel ListElement { type: "Dog" age: 8 noise: "meow" } ListElement { type: "Cat" age: 5 noise: "woof" } } component MyDelegate : Text { required property string type required property int age text: type + ", " + age // 間違った記述: Component.onCompleted: () => console.log(noise) // 必須プロパティであるnoiseがないため、ReferenceErrorが発生する // 必要プロパティが存在することで、スコープにノイズが注入されるのを防ぐことができる } ListView { anchors.fill: parent model: myModel delegate: MyDelegate {} } } </syntaxhighlight> <br> モデルのプロパティとデリゲートのプロパティの間に名前の衝突がある場合、代わりに修飾されたモデル名でロールにアクセスすることができる。<br> <br> 例えば、モデル内とデリゲート内の両方に同名のプロパティが存在する時、<br> デリゲート内のプロパティではなく、モデル内のプロパティを参照する場合、<code><モデルのID名>.<プロパティ名></code>と記述することにより参照できる。<br> <br> また、モデル内のインデックスを含む特別なインデックスロールもデリゲートで使用できる。<br> <br> <u>※注意</u><br> <u>このインデックスは、アイテムがモデルから削除されると<code>-1</code>に設定されることに注意すること。</u><br> <u>インデックスロールにバインドする場合、インデックスが<code>-1</code>になる可能性、つまり、アイテムが有効でなくなる可能性を考慮したロジックにする。</u><br> <u>(通常、アイテムはすぐに破棄されるが、一部のビューでは<code>delayRemove</code>プロパティによりデリゲートの破棄を遅らせることができる)</u><br> <br> 名前付きロールを持たないモデル(例. <code>ListModel</code>等)は、モデルデータロールによりデータが提供される。<br> モデルデータロールは、1つのロールしか持たないモデルにも提供される。この場合、モデルデータロールには、名前付きロールと同じデータが含まれる。<br> <br> <u>※注意</u><br> <u>モデルロール、モデルデータロール、インデックスロールにおいて、デリゲートが必須プロパティを含んでいる場合、プロパティ名が一致しなければアクセスできないことに注意する。</u><br> <br> QMLには、いくつかのデータモデルが用意されており、それらはQMLの組み込み型に含まれている。<br> 加えて、モデルはQt C++で作成することができ、そのモデルを<code>QQmlEngine</code>クラスを使用してQMLコンポーネントから利用することもできる。<br> <br> モデルの作成については、[[QMLの基礎 - モデルの作成]]や[[QMLの基礎 - QMLタイプの作成]]を参照すること。<br> <br> モデルからアイテムを配置する場合は、<code>Repeater</code>を使用することで実現できる。<br> <br> ==== ListModel ==== <code>ListModel</code>は、QMLで指定された単純な型の階層である。<br> 利用可能な役割は、<code>ListElement</code>プロパティで指定する。<br> <syntaxhighlight lang="qml"> ListModel { id: fruitModel ListElement { name: "Apple" cost: 2.45 } ListElement { name: "Orange" cost: 3.25 } ListElement { name: "Banana" cost: 1.95 } } </syntaxhighlight> <br> 上記の<code>ListModel</code>は、nameロールとcostロールの2つのロールを持っている。<br> これらは、例えば、<code>ListView</code>のデリゲートでバインドすることができる。<br> <syntaxhighlight lang="qml"> ListView { anchors.fill: parent model: fruitModel delegate: Row { Text { text: "Fruit: " + name } Text { text: "Cost: $" + cost } } } </syntaxhighlight> <br> <code>ListModel</code>には、JavaScriptから<code>ListModel</code>を直接操作するためのメソッドが用意されている。<br> この時、最初に挿入されたアイテムが、モデルを使用している全てのビューで利用可能なロールを決定する。<br> <br> 例えば、空の<code>ListModel</code>があり、JavaScript経由で入力された場合、最初の挿入によって提供されたロールがビューに表示される唯一のロールとなる。<br> <br> 以下の例では、初めて<code>MouseArea</code>の場所が押下する時、fruitModel(<code>ListModel</code>)にはcostロールとnameロールの2つのロールが追加される。<br> 次のロールが追加された場合も、モデルを使用するビューでは、最初の2つのロールのみが処理される。<br> <br> モデルで利用可能なロールをリセットするには、<code>ListModel::clear</code>メソッドを呼び出す必要がある。<br> <syntaxhighlight lang="qml"> ListModel { id: fruitModel } // ...略 MouseArea { anchors.fill: parent onClicked: { fruitModel.append({"cost": 5.95, "name":"Pizza"}) } } </syntaxhighlight> <br> ==== XmlListModel ==== <code>XmlListModel</code>では、XMLデータソースからモデルを構築することができる。<br> ロールは、<code>XmlRole</code>型で指定する。<br> <br> <code>XmlListModel</code>は、以下のモジュールをインポートする必要がある。<br> <syntaxhighlight lang="qml"> import QtQuick.XmlListModel 2.15 </syntaxhighlight> <br> 以下の例では、タイトル、リンク、説明の3つのロールを持っている。<br> <code>query</code>プロパティは、<code>XmlListModel</code>がXMLドキュメント内の各<code><item></code>エレメントに対して、モデルアイテムを生成することを指定する。<br> <syntaxhighlight lang="qml"> XmlListModel { id: feedModel source: "http://rss.news.yahoo.com/rss/oceania" query: "/rss/channel/item" XmlRole { name: "title" query: "title/string()" } XmlRole { name: "link" query: "link/string()" } XmlRole { name: "description" query: "description/string()" } } </syntaxhighlight> <br> [https://doc.qt.io/qt-5/qtdoc-demos-rssnews-example.html RSSニュースのデモ]では、<code>XmlListModel</code>を使用してRSSフィードを表示する方法を記載している。<br> <br> ==== ObjectModel ==== <code>ObjectModel</code>は、ビューで使用されるビジュアルアイテムを含んでいる。<br> <code>ObjectModel</code>をビューで使用する場合、<code>ObjectModel</code>には既に視覚的なデリゲート(アイテム)が含まれているため、ビューはデリゲートを必要としない。<br> <br> 以下の例では、3つの色付きの長方形を<code>ListView</code>に配置している。<br> <syntaxhighlight lang="qml"> import QtQuick 2.15 import QtQml.Models 2.15 Rectangle { ObjectModel { id: itemModel Rectangle { height: 30 width: 80 color: "red" } Rectangle { height: 30 width: 80 color: "green" } Rectangle { height: 30 width: 80 color: "blue" } } ListView { anchors.fill: parent model: itemModel } } </syntaxhighlight> <br> ==== 整数型モデル ==== 整数は、ある数の型を含むモデルとして使用できる。<br> この場合、モデルにはデータの役割はありません。<br> <br> 以下の例では、5つの要素を持つ<code>ListView</code>を作成している。<br> <br> <u>※注意</u><br> <u>整数モデルのアイテム数の制限は、100,000,000であることに注意すること。</u><br> <syntaxhighlight lang="qml"> Item { width: 200 height: 250 ListView { anchors.fill: parent model: 5 delegate: itemDelegate } Component { id: itemDelegate Text { text: "I am item number: " + index } } } </syntaxhighlight> <br> ==== C++データモデル ==== C++でモデルを定義して、それをQMLで使用することができる。<br> この仕組みは、既存のC++データモデルや複雑なデータセットをQMLに公開するのに便利である。<br> <br> 詳細は、[https://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html Using C++ Models with Qt Quick Views]の記事を参照すること。<br> <br><br> == Repeater == <code>Repeater</code>は、モデルのデータをもとに、ポジショナで使用するアイテムをテンプレートから作成する。<br> <code>Repeater</code>とポジショナを組み合わせることで、多くのアイテムを簡単に並べることができる。<br> <br> <code>Repeater</code>はポジショナの中に配置されて、ポジショナが配置したアイテムを生成する。<br> <br> 各<code>Repeater</code>は、モデルのプロパティで指定されたモデルのデータの各要素、および、<code>Repeater</code>内の子アイテムとして定義されたテンプレートアイテムを組み合わせて、多数のアイテムを作成する。<br> アイテムの総数は、モデルのデータ量によって決まる。<br> <br> 以下の例では、<code>Grid</code>内で<code>Repeater</code>を使用して、<code>Rectangle</code>を格子状に配置している。<br> <code>Repeater</code>は、<code>Grid</code>が5x5の配列で配置しており、計24個の<code>Rectangle</code>を作成している。<br> <syntaxhighlight lang="qml"> import QtQuick 2.15 Rectangle { width: 400 height: 400 color: "black" Grid { x: 5 y: 5 rows: 5 columns: 5 spacing: 10 Repeater { model: 24 Rectangle { width: 70 height: 70 color: "lightgreen" Text { text: index font.pointSize: 30 anchors.centerIn: parent } } } } } </syntaxhighlight> <br> <code>Repeater</code>が作成するアイテムの数は<code>Repeater.count</code>プロパティで保持されるが、このプロパティは読み込み専用のため設定することができない。<br> そのため、上記の例のように、<code>Repeater.model</code>プロパティにアイテムの数を設定する。<br> <br> モデルが文字列リストの場合、デリゲートは文字列を保持する読み取り専用の<code>Repeater.modelData</code>プロパティにも保持される。<br> 以下の例では、<code>Repeater.model</code>プロパティのリスト配列を<code>Text.text</code>プロパティに順に設定して、<code>Text</code>を配置している。<br> [[ファイル:QML Model and View 5.png|フレームなし|中央]] <syntaxhighlight lang="qml"> Column { Repeater { model: ["apples", "oranges", "pears"] Text { text: "Data: " + modelData } } } </syntaxhighlight> <br> また、<code>Repeater</code>が作成するアイテムのテンプレートとして、デリゲートを使用することもできる。<br> これは、<code>delegate</code>プロパティで指定する。<br> <br><br> __FORCETOC__ [[カテゴリ:Qt]]
QMLの基礎 - モデルとビュー
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse