实用指南:Qt/QML ListView组件基础用法示例

QML 中的 ListView 是 Qt Quick 框架中用于展示线性滚动列表的核心组件,遵循经典的 ** 模型-视图-代理(Model-View-Delegate)** 模式。它继承自 Flickable,天生支持触摸/鼠标滚动、惯性滑动等交互,同时提供了丰富的内置功能(如分组、动态加载、动画过渡)和高度的可定制性。
本文示例,采用Qt5.15进行开发。
一、核心设计理念:模型-视图-代理(MVD)
ListView 的设计遵循 Qt 的 MVD 模式,将数据逻辑、视图展示和项渲染分离:
- •模型(Model):负责提供数据(如列表项的内容、数量、分组信息)。
- •视图(ListView):负责管理布局、滚动、交互等视图逻辑。
- •代理(Delegate):负责将模型中的单条数据渲染为具体的 QML 组件(即列表项的外观)。
二、基础用法
1. 导入模块与基本结构
首先导入 Qt Quick 模块:
import QtQuick 2.15
import QtQuick.Window 2.15
创建一个简单的 ListView:
Window {
width: 400; height: 600
visible: true
// 1. 定义数据模型(ListModel)
ListModel {
id: myModel
ListElement { text: "Item 1"; color: "lightblue" }
ListElement { text: "Item 2"; color: "lightgreen" }
ListElement { text: "Item 3"; color: "salmon" }
// ... 更多项
}
// 2. 创建 ListView
ListView {
id: myList
anchors.fill: parent
anchors.margins: 10
// 绑定模型
model: myModel
// 定义代理(每个列表项的渲染模板)
delegate: Rectangle {
// 关键:获取视图宽度,让项填满列表宽度
width: ListView.view.width - 20
height: 60
radius: 8
color: model.color // 访问模型的数据
// 显示文本(访问模型的 text 属性)
Text {
text: model.text
anchors.centerIn: parent
font.pixelSize: 18
}
// 鼠标悬停效果
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: parent.color = "gray"
onExited: parent.color = model.color
onClicked: console.log("Clicked:", model.text)
}
}
// 可选:添加滚动条
ScrollBar.vertical: ScrollBar {
policy: ScrollBar.AlwaysOn // 始终显示滚动条
}
}
}
三、关键组件详解
1. 数据模型(Model)
ListView 支持多种模型,从简单的 ListModel 到自定义的 C++ 模型(QAbstractItemModel 子类)。
(1)简单模型:ListModel
ListModel 是 Qt Quick 内置的轻量级模型,适合静态或少量动态数据:
ListModel {
id: fruitModel
ListElement { name: "Apple"; price: 5; icon: "apple.png" }
ListElement { name: "Banana"; price: 3; icon: "banana.png" }
ListElement { name: "Orange"; price: 4; icon: "orange.png" }
}
- •
ListElement:定义单条数据的结构(属性名对应代理中的model.xxx)。
(2)自定义模型:C++ QAbstractItemModel
对于大量数据或复杂逻辑(如数据库查询、网络加载),建议用 C++ 实现 QAbstractListModel 或 QAbstractItemModel,再注册到 QML 中:
- •C++ 端:实现
rowCount()(返回项数)、data(const QModelIndex &index, int role)(返回指定角色数据)等方法。 - •QML 端:注册模型类型后使用:
import com.example.models 1.0 ListView { model: FruitModel {} // 自定义 C++ 模型 delegate: ... }
2. 代理(Delegate)
代理是 ListView 的核心定制点,决定了每个列表项的外观和交互。代理是一个 QML 组件,会为模型的每一条数据生成一个实例。
(1)访问模型数据
代理通过以下方式访问模型数据:
- •
modelData:通用属性,对应ListModel中的单条数据(或自定义模型的默认角色)。 - •
model.roleName:访问自定义模型的特定角色(如model.name、model.price)。 - •
index:当前项的索引(从 0 开始)。
(2)常用技巧
- •动态样式:根据索引或数据改变外观(如奇偶行不同颜色):
delegate: Rectangle { color: index % 2 === 0 ? "white" : "#f0f0f0" // ... } - •交互处理:通过
MouseArea或TapHandler处理点击、长按等事件。 - •性能优化:避免在代理中使用复杂计算或大量子项,减少重绘开销。
3. 视图属性与配置
ListView 提供了丰富的属性调整布局和行为:
| 属性/方法 | 说明 |
|---|---|
orientation | 布局方向(默认 Qt.Vertical,可设为 Qt.Horizontal 水平列表) |
spacing | 列表项之间的间距(默认 0) |
clip | 是否裁剪超出视图的内容(默认 true,防止项溢出) |
cacheBuffer | 预渲染的项数(如设为 100,会提前渲染当前可见项前后各 100 项,提升滚动流畅度) |
boundsBehavior | 滚动到边界的行为(Flickable.StopAtBounds 停止,Flickable.Overshoot 允许越界) |
currentIndexChanged | 当前选中项索引改变时触发的信号 |
currentIndex / currentItem | 获取/设置当前选中项的索引或组件实例 |
count | 列表项的总数(只读) |
4. 高级功能
(1)分组(Sections)
通过 section 属性实现列表分组(如按首字母分组):
ListView {
model: fruitModel
// 分组依据:name 属性的首字母
section.property: "name"
section.criteria: ViewSection.FullString
section.delegate: Rectangle {
width: ListView.view.width
height: 40
color: "gray"
Text {
text: section // 分组标题(如 "A"、"B")
anchors.centerIn: parent
font.bold: true
}
}
}
(2)动态加载(Lazy Loading)
对于超长列表,用 cacheBuffer 预渲染 + 动态加载内容(如图片):
delegate: Rectangle {
// ...
Image {
source: model.icon
asynchronous: true // 异步加载图片
placeholder: Rectangle { color: "lightgray" } // 加载中的占位符
}
}
(3)动画过渡
为项的添加、删除、移动添加动画,提升用户体验:
ListView {
// 添加项时的动画:淡入
add: Transition {
NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 200 }
}
// 删除项时的动画:淡出
remove: Transition {
NumberAnimation { property: "opacity"; from: 1; to: 0; duration: 200 }
}
}
(4)与其他组件联动
- •ScrollBar:自定义滚动条样式或行为:
ScrollBar.vertical: ScrollBar { width: 8 contentItem: Rectangle { radius: 4 color: "gray" implicitWidth: 4 } } - •SectionScroller:快速跳转到分组:
SectionScroller { listView: myList position: Qt.TopEdge }
四、信号与槽
ListView 提供了多个信号处理交互:
- •
clicked(index, model):点击项时触发。 - •
pressed(index, model):按下项时触发。 - •
doubleClicked(index, model):双击项时触发。 - •
movementEnded():滚动停止时触发。 - •
currentIndexChanged(int index):当前选中项改变时触发。
示例:
ListView {
// ...
onClicked: (index, model) => {
console.log("Clicked item:", index, model.text)
currentIndex = index // 设置为当前选中项
}
}
五、性能优化建议
- 1.减少代理复杂度:避免在代理中使用昂贵的计算、动画或大量子项。
- 2.合理设置 cacheBuffer:根据列表长度调整,避免内存浪费或滚动卡顿。
- 3.异步加载资源:图片、网络数据用
asynchronous属性异步加载。 - 4.数据更新通知:自定义模型需正确触发
dataChanged、rowsInserted等信号,让ListView及时刷新。 - 5.避免频繁滚动:如需高频更新内容,可使用
Timer节流。
总结
ListView 是 Qt Quick 中灵活、高效的线性列表组件,通过模型-视图-代理模式实现了数据与视图的分离。

惠州西湖
浙公网安备 33010602011771号