跳转到内容

第 5 课:Repeater、ListModel、ListView ​

更新: 10/23/2026 字数: 0 字 时长: 0 分钟

这一课分三步:

  1. Repeater:重复生成元素
  2. ListModel:定义数据
  3. ListView:显示数据列表 + 委托(delegate)

使用 Repeater、ListModel 与 ListView 展示列表数据 ​

1. Repeater:重复生成 ​

上一课你已经见过 Repeater。它的作用是:根据 model 数量,重复生成子元素。

qml
import QtQuick
import QtQuick.Window

Window {
    width: 320
    height: 320
    visible: true

    Column {
        anchors.centerIn: parent
        spacing: 6

        Repeater {
            id: i
            model: 5
            Rectangle {
                id: rect
                required property int index

                width: 200
                height: 40
                color: "lightblue"

                Text {
                    anchors.centerIn: parent
                    text: "第 " + (parent.index + 1) + " 项"
                }
            }
        }
    }
}

关键点:

  • model: 5 表示重复 5 次。
  • index 是 Repeater 自动提供的当前序号,从 0 开始。
  • 每个 Rectangle 是 Repeater 的子元素,被放进 Column 里排列。

Repeater 本身不显示任何东西,它只是“复制机”。


2. ListModel:结构化数据 ​

model: 5 只能重复固定次数。真实场景里,数据通常是有字段的。用 ListModel:

qml
ListModel {
    id: fruitModel

    ListElement { name: "苹果"; price: 5 }
    ListElement { name: "香蕉"; price: 3 }
    ListElement { name: "橙子"; price: 4 }
}

每个 ListElement 是一条数据,字段自定义。这里定义了 name 和 price。


3. ListView + delegate ​

ListView 是滚动列表视图,它需要一个 model 和一个 delegate。

delegate 是“每条数据怎么显示”的模板。

qml
import QtQuick
import QtQuick.Window

Window {
    width: 320
    height: 480
    visible: true
    title: "第五课"

    ListModel {
        id: fruitModel

        ListElement { name: "苹果"; price: 5 }
        ListElement { name: "香蕉"; price: 3 }
        ListElement { name: "橙子"; price: 4 }
        ListElement { name: "葡萄"; price: 8 }
        ListElement { name: "西瓜"; price: 12 }
    }

    ListView {
        anchors.fill: parent
        model: fruitModel
        spacing: 4

        delegate: Rectangle {
            required property string name
            required property int price

            width: ListView.view.width
            height: 60
            color: "lightyellow"
            border.color: "gray"

            Text {
                anchors.left: parent.left
                anchors.verticalCenter: parent.verticalCenter
                anchors.leftMargin: 12
                text: parent.name
                font.pixelSize: 20
            }

            Text {
                anchors.right: parent.right
                anchors.verticalCenter: parent.verticalCenter
                anchors.rightMargin: 12
                text: parent.price + " 元"
                font.pixelSize: 20
                color: "tomato"
            }
        }
    }
}

运行后你会看到一个可滚动的列表,每行显示水果名和价格。


关键点讲解 ​

1. delegate 里能直接访问模型字段 ​

在 delegate 内部,可以直接写:

qml
text: name
text: price + " 元"

不需要 fruitModel.get(index).name,QML 会自动把当前行的字段暴露给委托。

2. index 也能用 ​

delegate 里还能用 index,表示当前行号,从 0 开始。

qml
text: (index + 1) + ". " + name

3. ListView.view ​

在 delegate 里,ListView.view 指向所在的 ListView。

qml
width: ListView.view.width

让每行宽度等于列表宽度,这是常见写法。

也可以用:

qml
width: parent.width

但 parent 在委托里有时不一定是 ListView,所以推荐用 ListView.view.width。

4. spacing ​

ListView 的 spacing 控制行间距。

你的动手练习 ​

练习 1 ​

在 ListModel 里再加两条数据,观察列表是否能滚动。

练习 2 ​

在 delegate 里加一行序号:

qml
text: (index + 1) + ". " + name

练习 3 ​

点击某一行时,在控制台打印它的名字。

提示:在 delegate 的 Rectangle 里加:

qml
MouseArea {
    anchors.fill: parent
    onClicked: console.log("点击了: " + name)
}

练习 4 ​

让奇数行和偶数行颜色不同:

qml
color: index % 2 === 0 ? "lightyellow" : "white"

练习 5(思考题) ​

如果 delegate 里写:

qml
text: name

但 ListModel 的字段叫 title,会发生什么?为什么?