今までの記事でもさっくり使ってるのですが、改めてListViewの使い方をまとめて見ました。
/// ListViewの動作ポイント ///
・Model情報を解析して表示可能範囲のアイテムが1つずつ動的にインスタンス化される
・delegateに設定されたレイアウトが使い回される
・動的にインスタンス化されるのでいつもとidの値などの扱いが違う
サンプルで上位に自分のインスタンスを「_layout1」をクリックイベント内で「clickList」へ渡してます。
見た目は共通になるイメージですが、実体はそれぞれのアイテムで別になります。
そもそも「Listview.delegate: ListLayout{ ... }」としているので他の言語ならクラスをnewするイメージです。
逆にエレメントのプロパティに他のエレメントのidを指定する時はポインタを渡してる感じですね。
リストのアイテムは画面外にでると設定状態にあわせて破棄されます。
こんな感じ
このListViewとModelとDelegateの関係がちゃんと理解できると「Repeater」を使用して、Column/Row/Gridの利用幅が広がります。
以前の記事の「QML(Qt)でコンテキストメニューを表示する」のコンテキストメニューの部分で利用しています。
/// サンプル動作 ///
・リストのアイテムをクリックすると画面中心に情報を表示します。
・赤いボタンを押すとリストへフォーカスが移動してカーソルキーでハイライトが移動します。
・赤いボタンを押すと現在のハイライトアイテムの情報を表示します。
/// サンプルのポイント ///
・クリックしたアイテムの情報を取得する
・ハイライトの共通化
・クリックしたアイテムをハイライトする
/// クリックしたアイテムの情報を取得する ///
「ItemLayout.qml」内でMouseAreaを設定してクリックイベントをシグナルで上位に伝えれるようにしています。
その時、引数を定義すれば自分の保持している文字列などを渡せます。
delegateに指定したItemLayout{ /* ここ */} の中にStep1のイベントを受けて更に上位が持っているメソッドを呼び出せます。
この時、上にも書いてますがItemLayoutに指定したidをメソッドに渡すとクリックしたアイテムを操作できます。
/// ハイライトの共通化 ///
リストの現在のアイテムをハイライトする事ができます。
ListViewのヘルプや「Models and Views: ListView Example」を見ると簡単にできます。
ただ、この方法だとListViewが複数配置されているとハイライト用の情報を複数記述しないといけなくなってしまい冗長です。
なので共通化する方法です。
で、何が問題かと言うと。
下にListViewのヘルプにあるサンプルを用意しました。
ハイライトされているアイテムを目立たせるための四角の位置やサイズをListViewの情報を使ってるので共通化がしにくいのです。
公式サンプル転記
で、ハイライト用のコンポーネントはエレメントとして別ファイルに分けます「ItemHightlight.qml」がそうです。
ListView側は「highlight: ItemHightlight{ ... }」としてエレメントをidではなくインスタンスを生成して指定します。
こおすれば各ListViewに独立した情報を指定できるのです。
/// クリックしたアイテムをハイライトする ///
「ListView.currentIndex」を指定すればOKで簡単です。
でもクリックしたアイテムがリストの中で何番目かどのようにして知るか?です。
それも実はすごい簡単で「ListView.indexAt(x, y)」メソッドを使えば簡単にできます。
/// サンプルのスクリーンショット ///
リストの表示アイテムのレイアウト
ハイライト用の情報
リストへ表示する内容(右用)
<Category : Qt>
/// ListViewの動作ポイント ///
・Model情報を解析して表示可能範囲のアイテムが1つずつ動的にインスタンス化される
・delegateに設定されたレイアウトが使い回される
・動的にインスタンス化されるのでいつもとidの値などの扱いが違う
サンプルで上位に自分のインスタンスを「_layout1」をクリックイベント内で「clickList」へ渡してます。
見た目は共通になるイメージですが、実体はそれぞれのアイテムで別になります。
そもそも「Listview.delegate: ListLayout{ ... }」としているので他の言語ならクラスをnewするイメージです。
逆にエレメントのプロパティに他のエレメントのidを指定する時はポインタを渡してる感じですね。
リストのアイテムは画面外にでると設定状態にあわせて破棄されます。
こんな感じ
このListViewとModelとDelegateの関係がちゃんと理解できると「Repeater」を使用して、Column/Row/Gridの利用幅が広がります。
以前の記事の「QML(Qt)でコンテキストメニューを表示する」のコンテキストメニューの部分で利用しています。
/// サンプル動作 ///
・リストのアイテムをクリックすると画面中心に情報を表示します。
・赤いボタンを押すとリストへフォーカスが移動してカーソルキーでハイライトが移動します。
・赤いボタンを押すと現在のハイライトアイテムの情報を表示します。
/// サンプルのポイント ///
・クリックしたアイテムの情報を取得する
・ハイライトの共通化
・クリックしたアイテムをハイライトする
/// クリックしたアイテムの情報を取得する ///
「ItemLayout.qml」内でMouseAreaを設定してクリックイベントをシグナルで上位に伝えれるようにしています。
その時、引数を定義すれば自分の保持している文字列などを渡せます。
delegateに指定したItemLayout{ /* ここ */} の中にStep1のイベントを受けて更に上位が持っているメソッドを呼び出せます。
この時、上にも書いてますがItemLayoutに指定したidをメソッドに渡すとクリックしたアイテムを操作できます。
/// ハイライトの共通化 ///
リストの現在のアイテムをハイライトする事ができます。
ListViewのヘルプや「Models and Views: ListView Example」を見ると簡単にできます。
ただ、この方法だとListViewが複数配置されているとハイライト用の情報を複数記述しないといけなくなってしまい冗長です。
なので共通化する方法です。
で、何が問題かと言うと。
下にListViewのヘルプにあるサンプルを用意しました。
ハイライトされているアイテムを目立たせるための四角の位置やサイズをListViewの情報を使ってるので共通化がしにくいのです。
公式サンプル転記
Component { id: highlight Rectangle { width: 180; height: 40 color: "lightsteelblue"; radius: 5 y: list.currentItem.y Behavior on y { SpringAnimation { spring: 3 damping: 0.2 } } } } ListView { id: list width: 180; height: 200 model: ContactModel {} delegate: Text { text: name } highlight: highlight highlightFollowsCurrentItem: false focus: true }
で、ハイライト用のコンポーネントはエレメントとして別ファイルに分けます「ItemHightlight.qml」がそうです。
ListView側は「highlight: ItemHightlight{ ... }」としてエレメントをidではなくインスタンスを生成して指定します。
こおすれば各ListViewに独立した情報を指定できるのです。
/// クリックしたアイテムをハイライトする ///
「ListView.currentIndex」を指定すればOKで簡単です。
でもクリックしたアイテムがリストの中で何番目かどのようにして知るか?です。
それも実はすごい簡単で「ListView.indexAt(x, y)」メソッドを使えば簡単にできます。
/// サンプルのスクリーンショット ///
// main.qml import QtQuick 1.0 Rectangle { id: _root width: 350 height: 250 // リストの情報を表示 function clickList(list, object, itemText){ // クリックアイテムをハイライトする list.currentIndex = list.indexAt(object.x, object.y); // デバッグ表示 _debugText.text = "num : " + object.number + "\ntext : " + object.text + "\nitemText : " + itemText; } // リストの配置 Row{ spacing: 3 ListView{ id: _listLeft width: _root.width / 2 height: _root.height // ハイライト設定 highlight: ItemHightlight{ _listObject: _listLeft } // モデル model: Items1{} // デリゲート delegate: ItemLayout{ // インスタンスごとに生成される範囲 id: _layout1 // 表示レイアウトへ具体的な値をセットする number: _number text: arrangeText(_text) // 表示するデータをアレンジもOK function arrangeText(text){ return text + "(in left)"; } // クリックイベント onClicked: { // こんな風に更に上位へデータや自分のインスタンスを渡すのもできる clickList(_listLeft, _layout1, itemText); } } } ListView{ id: _listRight width: _root.width / 2 height: _root.height // ハイライト設定 highlight: ItemHightlight{ _listObject: _listRight } // モデル model: Items2{} // デリゲート delegate: ItemLayout{ // インスタンスごとに生成される範囲 id: _layout2 // 表示レイアウトへ具体的な値をセットする number: _number text: arrangeText(_text) // 表示するデータをアレンジもOK function arrangeText(text){ return text + "(in right)"; } // クリックイベント onClicked: { // こんな風に更に上位へデータや自分のインスタンスを渡すのもできる clickList(_listRight, _layout2, itemText); } } } } // 左のリストへフォーカスセットして現在の情報表示 Rectangle{ anchors.horizontalCenter: parent.horizontalCenter y: 0 width: 70 height: 20 color: "#dd0000" Text{ anchors.centerIn: parent text: "Focus left" } MouseArea{ anchors.fill: parent onClicked: { _listLeft.forceActiveFocus(); clickList(_listLeft, _listLeft.currentItem , "current selected"); } } } // 右のリストへフォーカスセットして現在の情報表示 Rectangle{ anchors.horizontalCenter: parent.horizontalCenter y: 22 width: 70 height: 20 color: "#dd0000" Text{ anchors.centerIn: parent text: "Focus right" } MouseArea{ anchors.fill: parent onClicked: { _listRight.forceActiveFocus(); clickList(_listRight, _listRight.currentItem , "current selected"); } } } // 情報表示 Rectangle{ x: _debugText.x y: _debugText.y width: _debugText.width height: _debugText.height color: "#555555" } Text{ id: _debugText anchors.centerIn: parent text: "" color: "#ffffff" } }
リストの表示アイテムのレイアウト
// ItemLayout.qml import QtQuick 1.0 Rectangle { id: _root width: 160 height: 60 // 枠線 border.color: "#dddddd" border.width: 1 // 実際に表示する部分へのエイリアス property alias number: _layoutNumber.text property alias text: _layoutText.text // 上位への通知用のシグナル signal clicked(string itemText) // 表示アイテムを配置 Row{ anchors.centerIn: parent spacing: 5 Text{ id: _layoutNumber width: 20 text: "" } Text{ id: _layoutText width: 80 text: "" } } // クリック判定 MouseArea{ anchors.fill: parent onClicked: { // クリックシグナルを上位へ _root.clicked(_layoutNumber.text + ":" + _layoutText.text); } } }
ハイライト用の情報
// ItemHightlight.qml import QtQuick 1.0 Rectangle { id: _root property variant _listObject: null width: (_listObject.currentItem === null) ? 0 : _listObject.currentItem.width height: (_listObject.currentItem === null) ? 0 : _listObject.currentItem.height y: (_listObject.currentItem === null) ? 0 : _listObject.currentItem.y; color: "#dddd00" Behavior on y { SpringAnimation { spring: 2; damping: 0.1 } } }リストへ表示する内容(左用)
// Items1.qml import QtQuick 1.0 ListModel{ id: _items ListElement{ _number: 0 _text: "first" } ListElement{ _number: 1 _text: "second" } ListElement{ _number: 2 _text: "third" } ListElement{ _number: 3 _text: "fourth" } ListElement{ _number: 4 _text: "fifth" } ListElement{ _number: 5 _text: "sixth" } ListElement{ _number: 6 _text: "seventh" } }
リストへ表示する内容(右用)
// Items2.qml import QtQuick 1.0 ListModel{ id: _items ListElement{ _number: 0 _text: "FIRST" } ListElement{ _number: 1 _text: "SECOND" } ListElement{ _number: 2 _text: "THIRD" } ListElement{ _number: 3 _text: "FOURTH" } ListElement{ _number: 4 _text: "FIFTH" } ListElement{ _number: 5 _text: "SIXTH" } ListElement{ _number: 6 _text: "SEVENTH" } }