6.Model-View-Delegate
** 注意: **
最新的構(gòu)建時間:2016/03/21
這章的源代碼能夠在assetts folder找到。
在 Qt Quick 中,數(shù)據(jù)被通過模型(model 下同)-視圖(view 下同)分離的方式分離出來。對于每個視圖,每個數(shù)據(jù)元素的可視化都被分離成一個代理(delegate 下同)。Qt Quick 附帶一組預(yù)定義的模型和視圖類。要利用這個系統(tǒng),我們必須了解這些類,并知道如何創(chuàng)建合適的代理以獲得正確的呈現(xiàn)效果。
6.1 概念
在開發(fā)用戶界面時,最重要的一個模式是保持?jǐn)?shù)據(jù)部分與可視化部分的分離。例如,電話本可以被安排為一個垂直的文本條目列表或聯(lián)系人的圖片網(wǎng)格。在這兩種情況下,數(shù)據(jù)部分都是相同的:電話簿,只是可視化部分的呈現(xiàn)方式不同而已。這種劃分通常被稱為 模型-視圖 模式。在這個模式中,數(shù)據(jù)部分被稱為模型(model),而可視化部分是由視圖(view)處理的。
在 QML 中,模型(model)和視圖(view)是由代理(delegate)連接起來的。責(zé)任分為以下幾點。該模型提供了數(shù)據(jù)。對于每個數(shù)據(jù)項,可能有多個值。在上面提到的電話本的例子中,最簡單的電話本條目基本上是由一個名稱、一個頭像和一串電話數(shù)字?jǐn)?shù)字組成。數(shù)據(jù)被排列在視圖(view)中,在視圖(view)中,每個項目都使用代理(delegate)進(jìn)行可視化的處理。視圖(view)的任務(wù)是對代理進(jìn)行排列,而每個代理(delegate)將每個模型(model)項的值顯示給用戶。

6.2 基本模型
將數(shù)據(jù)從視圖顯示中分離出來的最基本的方法是使用 Repeater 元素。它用于實例化一個 QML 可視元素的數(shù)組,并且很容易與定位器相結(jié)合來填充用戶界面的一部分。Repeater 有一個模型(model)屬性,它可以是使用任意 QML 可視元素的數(shù)量來作為值進(jìn)行實例化,也可以是從網(wǎng)絡(luò)上獲取數(shù)據(jù)的完整的數(shù)據(jù)模型。
在最簡單的形式中,Repeater 可以用來實例化指定數(shù)量的 QML 可視元素。每個條目都可以訪問一個附加的屬性,變量索引(index),它可以用來區(qū)分不同的條目。在下面的例子中,一個 Repeater 被用來創(chuàng)建一個有10個項目實例的視圖。項目的數(shù)量由 model 屬性控制。對于 Repeater 中的已經(jīng)實例化的每一項都是一個 Rectangle 元素中包含著一個 Text 元素。正如你看到的,Text 元素的 text 屬性被設(shè)置為 index 的值,因此項目是從 0 到 9 顯示的。
下面是示例 Example 01:
import QtQuick 2.5
import "../common"
Column {
spacing: 2
Repeater {
model: 10
BlueBox {
width: 120
height: 32
text: index
}
}
}

有編號的條目列表看起來似乎很不錯,但是顯示一個更復(fù)雜的數(shù)據(jù)集可能更有趣也更符合我們的實際需要。我們可以通過使用 JS 數(shù)組替換掉原有的數(shù)字值作為 model 的值來實現(xiàn)我們的想法。數(shù)組的內(nèi)容可以是任何類型的,無論是字符串、整數(shù)還是對象。在下面的例子中,使用了一個字符串列表。這時,我們在仍然可以訪問和使用索引變量(index)的同時,我們也可以使用包含數(shù)組中每個元素的數(shù)據(jù)的 modelData 屬性。
import QtQuick 2.5
import "../common"
Column {
spacing: 2
Repeater {
model: ["Enterprise", "Columbia", "Challenger", "Discovery", "Endeavour", "Atlantis"]
BlueBox {
width: 100
height: 32
radius: 3
text: modelData + ' (' + index + ')'
}
}
}

由于能夠公開一個數(shù)組的數(shù)據(jù),我們很快就會發(fā)現(xiàn)自己需要數(shù)組中的每一項可以包含多個數(shù)據(jù)項。ListModel 是最簡單,也是最常用的模型之一。ListModel 是 ListElement 元素的集合。 在每個列表元素內(nèi),可以將多個屬性和其對應(yīng)的值綁定。 例如,在下面的示例中,為每個元素提供了一個名稱和顏色。
每個元素內(nèi)的屬性被 Repeater 附加到每個實例化的項。這意味著變量 name 和 surfaceColor 可以在由 Repeater 創(chuàng)建的每個 Rectangle 和 Text 項目的范圍內(nèi)使用。這不僅使訪問數(shù)據(jù)變得容易,還可以輕松地讀取源代碼。surfaceColor 是名稱左側(cè)的圓圈的顏色,這是很形象的,而不是像第 j 行的 i 列的數(shù)據(jù)那樣模糊的概念。
import QtQuick 2.5
import "../common"
Column {
spacing: 2
Repeater {
model: ListModel {
ListElement { name: "Mercury"; surfaceColor: "gray" }
ListElement { name: "Venus"; surfaceColor: "yellow" }
ListElement { name: "Earth"; surfaceColor: "blue" }
ListElement { name: "Mars"; surfaceColor: "orange" }
ListElement { name: "Jupiter"; surfaceColor: "orange" }
ListElement { name: "Saturn"; surfaceColor: "yellow" }
ListElement { name: "Uranus"; surfaceColor: "lightBlue" }
ListElement { name: "Neptune"; surfaceColor: "lightBlue" }
}
BlueBox {
width: 120
height: 32
radius: 3
text: name
Box {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 4
width: 16
height: 16
radius: 8
color: surfaceColor
}
}
}
}

正在為每個項目實例化的 Repeater 的內(nèi)容實際上是綁定到默認(rèn)屬性,delegate 的內(nèi)容。這意味著 Example 01 的代碼與下面顯示的代碼同義。請注意,唯一的區(qū)別是 delegate 屬性名稱在后者中被明確列出。
import QtQuick 2.5
import "../common"
Column {
spacing: 2
Repeater {
model: 10
delegate: BlueBox {
width: 100
height: 32
text: index
}
}
}