前面的章节我们介绍过模型视图。这是一种数据和显示相分离的技术,在 Qt 中有着非常重要的地位。在 QtQuick 中,数据和显示的分离同样也是利用这种“模型-视图”技术实现的。对于每一个视图,数据元素的可视化显示交给代理完成。与 Qt/C++ 类似,QtQuick 提供了一系列预定义的模型和视图。本章开始,我们着重介绍这部分内容。这部分内容主要来自http://qmlbook.org/ch06/index.html,在此表示感谢。

    由于 QtQuick 中的模型视图的基本概念同前面的章节没有本质的区别,所以这里不再赘述这部分内容。

    将数据从表现层分离的最基本方法是使用Repeater元素。Repeater元素可以用于显示一个数组的数据,并且可以很方便地在用户界面进行定位。Repeater的模型范围很广:从一个整型到网络数据,均可作为其数据模型。

    Repeater最简单的用法是将一个整数作为其model属性的值。这个整型代表Repeater所使用的模型中的数据个数。例如下面的代码中,model: 10代表Repeater的模型有 10 个数据项。

    1. import QtQuick 2.2
    2.  
    3. Column {
    4. spacing: 2
    5. Repeater {
    6. model: 10
    7. Rectangle {
    8. width: 100
    9. height: 20
    10. radius: 3
    11. color: "lightBlue"
    12. Text {
    13. anchors.centerIn: parent
    14. text: index
    15. }
    16. }
    17. }
    18. }

    现在我们设置了 10 个数据项,然后定义一个Rectangle进行显示。每一个Rectangle的宽度和高度分别为 100px 和 20px,并且有圆角和浅蓝色背景。Rectangle中有一个Text元素为其子元素,Text文本值为当前项的索引。代码运行结果如下:

    Repeater 示例

    虽然指定模型项的个数很简单,但实际用处不大。Repeater还支持更复杂的方式,例如,把一个 JavaScript 数组作为模型。JavaScript 数组元素可以是任意类型:字符串、数字或对象。在下面的例子中,我们将一个字符串数组作为Repeater的模型。我们当然可以使用index获得当前索引,同时,我们也可以使用modelData访问到数组中的每一个元素的值:

    1. import QtQuick 2.2
    2.  
    3. Column {
    4. spacing: 2
    5. Repeater {
    6. model: ["Enterprise", "Colombia", "Challenger", "Discovery", "Endeavour", "Atlantis"]
    7. Rectangle {
    8. width: 100
    9. height: 20
    10. radius: 3
    11. color: "lightBlue"
    12. Text {
    13. anchors.centerIn: parent
    14. text: index +": "+modelData
    15. }
    16. }
    17. }
    18. }

    代码运行结果如下:Repeater 数组模型

    由于能够使用 JavaScript 数组作为Repeater的模型,而 JavaScript 数组能够以对象作为其元素类型,因而Repeater就可以处理复杂的数据项,比如带有属性的对象。这种情况其实更为常见。相比普通的 JavaScript 对象,更常用的是ListElement类型。类似普通 JavaScript 对象,每一个ListElement可以有任意属性。例如下面的代码示例中,每一个数据项都有一个名字和外观颜色。

    1. import QtQuick 2.2
    2.  
    3. Column {
    4. spacing: 2
    5. Repeater {
    6. model: ListModel {
    7. ListElement { name: "Mercury"; surfaceColor: "gray" }
    8. ListElement { name: "Venus"; surfaceColor: "yellow" }
    9. ListElement { name: "Earth"; surfaceColor: "blue" }
    10. ListElement { name: "Mars"; surfaceColor: "orange" }
    11. ListElement { name: "Jupiter"; surfaceColor: "orange" }
    12. ListElement { name: "Saturn"; surfaceColor: "yellow" }
    13. ListElement { name: "Uranus"; surfaceColor: "lightBlue" }
    14. ListElement { name: "Neptune"; surfaceColor: "lightBlue" }
    15. }
    16.  
    17. Rectangle {
    18. width: 100
    19. height: 20
    20. radius: 3
    21. color: "lightBlue"
    22. Text {
    23. anchors.centerIn: parent
    24. text: name
    25. }
    26.  
    27. Rectangle {
    28. anchors.left: parent.left
    29. anchors.verticalCenter: parent.verticalCenter
    30. anchors.leftMargin: 2
    31.  
    32. width: 16
    33. height: 16
    34. radius: 8
    35. border.color: "black"
    36. border.width: 1
    37.  
    38. color: surfaceColor
    39. }
    40. }
    41. }
    42. }

    运行结果如下图所示:

    Repeater 使用 ListElement

    ListElement的每个属性都被Repeater绑定到实例化的显示项。正如上面代码中显示的那样,这意味着每一个用于显示数据的Rectangle作用域内都可以访问到ListElementnamesurfaceColor属性。

    像上面几段代码中,Repeater的每一个数据项都使用一个Rectangle渲染。事实上,这是由于Repeater具有一个delegate的默认属性,由于Rectangle没有显式赋值给任何一个属性,因此它直接成为默认属性delegate的值,所以才会使用Rectangle渲染。理解了这一点,我们就可以写出具有显式赋值的代码:

    1. import QtQuick 2.2
    2.  
    3. Column {
    4. spacing: 2
    5. Repeater {
    6. model: 10
    7. delegate: Rectangle {
    8. width: 100
    9. height: 20
    10. radius: 3
    11. color: "lightBlue"
    12. Text {
    13. anchors.centerIn: parent
    14. text: index
    15. }
    16. }
    17. }
    18. }

    实际上,这段代码与前面提到的是等价的。