
1. 模型-视图-委托Model-View-Delegate架构QML 沿用 Qt 经典的 MVC 思想但把 Controller 弱化信号/绑定承担职责角色职责例子Model提供数据行/字段/顺序ListModel、XmlListModel、C QAbstractListModel、JS 数组View遍历模型按需创建委托ListView、GridView、TableView、PathView、RepeaterDelegate渲染单条数据处理交互自定义 Component关键点View 只创建可见区域 缓存区的委托虚拟化所以百万条数据也能流畅滚动——这是 QML 列表性能的根基。2. Repeater —— 最简单的视图Repeater 不滚动、不虚拟化适合少量静态数据Column { Repeater { model: [苹果, 香蕉, 橙子] delegate: Text { text: 水果 modelData } } }Repeater 的 delegate 中可用变量变量含义index当前序号从 0 开始modelData当前数据项数组/整数模型时model整个模型或对象模型时表示当前项数据量大50时别用 Repeater——它一次性创建全部委托无虚拟化。3. ListView —— 列表视图重点3.1 最小完整示例import QtQuick ListView { width: 300 height: 400 model: ListModel { ListElement { name: 张三; age: 20 } ListElement { name: 李四; age: 22 } ListElement { name: 王五; age: 24 } } delegate: Rectangle { width: parent.width height: 40 color: index % 2 0 ? #f8f8f8 : #ffffff border.color: #e0e0e0 Text { anchors.left: parent.left anchors.leftMargin: 12 anchors.verticalCenter: parent.verticalCenter text: name 年龄 age // 直接访问模型字段 } } }delegate 里直接按字段名访问模型数据name、age这是 QML 的便捷机制。3.2 常用属性ListView { model: myModel delegate: myDelegate orientation: ListView.Vertical // 或 Horizontal spacing: 4 // 项间距 cacheBuffer: 400 // 预渲染缓冲像素 clip: true // 裁剪防止滚动时露出内容 snapMode: ListView.SnapToItem // 吸顶/吸附 highlightRangeMode: ListView.ApplyRange // 高亮跟随 preferredHighlightBegin: 0 preferredHighlightEnd: 100 currentIndex: 0 // 当前项 // 信号 onCurrentIndexChanged: console.log(current, currentIndex) onMovementEnded: console.log(滚动了) }3.3 highlight 与滚动定位ListView { id: list model: 20 delegate: Rectangle { width: list.width; height: 40 color: index list.currentIndex ? #d0e8ff : white Text { anchors.centerIn: parent; text: 第 index 项 } MouseArea { anchors.fill: parent onClicked: list.currentIndex index } } highlight: Rectangle { color: #d0e8ff } // 高亮背景可动画 highlightMoveDuration: 200 // 高亮移动动画时长 highlightFollowsCurrentItem: true }3.4 数据操作ListModel 增删改ListModel { id: model ListElement { name: A } ListElement { name: B } } // 追加 / 插入 / 修改 / 删除 Button { onClicked: model.append({ name: C }) } Button { onClicked: model.insert(0, { name: Z }) } Button { onClicked: model.setProperty(1, name, B2) } Button { onClicked: model.remove(0) } Button { onClicked: model.clear() }ListModel 的每个元素是 ListElement字段用 role 表示。增删改后 View 自动刷新——这就是数据驱动 UI。3.5 动态模型JS 数组作 modelListView { model: [10, 20, 30] // JS 数组 delegate: Text { text: 值 modelData // 数组项用 modelData } }model: 5整数时 delegate 只拿到 index常用于占位/分页。3.6 ListView 性能要点优化说明delegate 用 Item 代替复杂 Rectangle减少绘制图片设 sourceSize缩小解码内存少用阴影/透明效果滚动时开销大cacheBuffer 合理设置太大浪费太小滚动白屏不要放重计算绑定delegate 的绑定每项都会求值大量复杂项用 Recycle见后文委托复用3.7 委托复用RecycleQt 5.15/Qt6委托对象会被 View 复用item 移动而非重建需要在 onReused 里重置状态Component { id: delegateComp Rectangle { width: 200; height: 40 property int itemIndex Text { text: itemIndex } Component.onCompleted: console.log(created) // 只会执行有限次 onReused: { // 复用回调 color #ffffff // 重置残留状态 itemIndex model.index } } } ListView { model: 10000 delegate: delegateComp reuseItems: true // 开启委托复用默认 false }开启 reuseItems 后不要再依赖 Component.onCompleted 做每项初始化改在 onReused 处理。4. GridView / PathView / TableView4.1 GridView —— 网格GridView { width: 320; height: 320 cellWidth: 100 cellHeight: 100 model: 20 delegate: Rectangle { width: 90; height: 90 radius: 8 color: hsl( (index * 18) , 60%, 60%) Text { anchors.centerIn: parent; text: index } } }4.2 PathView —— 路径滚动封面流PathView { width: 400; height: 200 model: 10 path: Path { startX: 0; startY: 100 PathQuad { x: 200; y: 100 } PathQuad { x: 400; y: 100 } } delegate: Rectangle { width: 120; height: 120 radius: 8 color: steelblue Text { anchors.centerIn: parent; text: index; color: white } } }PathView 适合卡片轮播效果性能比 ListView 差数据不宜过多。4.3 TableViewQt5.12 / Qt6import QtQuick import QtQuick.Controls TableView { width: 400; height: 300 model: myTableModel // 建议 C QAbstractTableModel delegate: Rectangle { implicitHeight: 36 color: row tableView.currentRow ? #e0f0ff : (row % 2 0 ? #fafafa : white) Text { anchors.fill: parent anchors.margins: 8 verticalAlignment: Text.AlignVCenter text: display // 表模型 roledisplay } } }复杂表格排序/编辑/多列强烈建议用 C QAbstractTableModel TableView详见 04 章。5. Component 与自定义组件5.1 什么是 ComponentComponent 是可复用模板。两种形态独立 .qml 文件MyButton.qml 本身就是一个 Component。内联 Component 元素在一个文件里定义可复用模板。// 内联 Component Component { id: myText Text { font.pixelSize: 18; color: #333 } } Column { Repeater { model: 3 delegate: Loader { sourceComponent: myText; onLoaded: item.text 条目 index } } }5.2 自定义组件文件MyCard.qml// MyCard.qml import QtQuick Rectangle { id: root width: 200 height: 80 radius: 10 color: #f0f4f8 border.color: #d0d7de // 对外暴露属性供使用方设置 property string title: property string subtitle: property color accentColor: #3d5a80 // 对外暴露信号 signal clicked() Column { anchors.centerIn: parent spacing: 4 Text { anchors.horizontalCenter: parent.horizontalCenter text: root.title font.pixelSize: 18 font.bold: true color: root.accentColor } Text { anchors.horizontalCenter: parent.horizontalCenter text: root.subtitle font.pixelSize: 12 color: gray } } MouseArea { anchors.fill: parent onClicked: root.clicked() } }使用import QtQuick Column { MyCard { title: 标题 A subtitle: 副标题说明 onClicked: console.log(点击 A) } MyCard { title: 标题 B accentColor: #e63946 } }5.3 组件规范团队最佳实践规范说明文件首字母大写MyCard.qml根对象必须 id: root内部引用统一用 root.xxx对外 API 用 property signal不要暴露内部实现细节对外属性命名语义化title、subtitle、accentColor内部元素 id 不对外使用方不能访问内部 id复杂组件加文档注释/// 卡片组件显示标题与副标题提供合理默认值属性都给默认值避免使用方必须设置用 Qt.styleHints / 主题统一风格颜色/字体从主题读取5.4 property alias —— 属性转发// MyButton.qml Rectangle { id: root property alias text: label.text // 把 label.text 暴露为 text property alias textColor: label.color Text { id: label anchors.centerIn: parent text: color: white } }alias 限制只能转发属性不能转发绑定表达式别名不能重复命名别名不能参与循环property alias a: b property alias b: a 禁止。5.5 Loader —— 按需加载Loader { id: contentLoader anchors.fill: parent source: showPage ? Page2.qml : Page1.qml // 或 sourceComponent: someComponent onLoaded: item.someProperty 1 }Loader 适用按需加载大组件、延迟初始化、多页面切换。item 是加载出的根对象。5.6 常用组件模式封装 vs 继承QML 没有传统继承组合优先需要换皮给组件加 property 内部 delegate。需要扩展用 Loader default property 嵌入子内容// Panel.qml Rectangle { id: root default property alias content: contentItem.data // 子对象直接进 contentItem Rectangle { id: contentItem anchors.fill: parent anchors.margins: 10 } } // 使用 Panel { Text { text: 我直接放在 Panel 里 } }6. 样式与主题6.1 Controls 2 的样式体系Qt Quick Controls 2 通过控件风格Style管理外观Default默认风格。Basic基础风格可定制。Fusion桌面风跨平台一致。MaterialMaterial DesignAndroid 风。UniversalWindows 10 风。Imagine纯图片驱动风格可换肤。运行时选择Cqputenv(QT_QUICK_CONTROLS_STYLE, Fusion);或配置文件 qtquickcontrols2.conf[Controls] StyleFusion6.2 自定义控件外观的三种方式方式 A修改内建 Style推荐入门import QtQuick.Controls.Fusion Button { text: Fusion 风格 }方式 B写自定义 Style 文件Qt6QtQuick/Controls.2/Style/Button.qml方式 C直接用 contentItem / background 属性定制灵活Button { text: 自定义按钮 background: Rectangle { radius: 8 color: parent.hovered ? #3d5a80 : (parent.pressed ? #1d3557 : #457b9d) } contentItem: Text { text: parent.text color: white horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } }6.3 主题变量统一工程实践用单例管理颜色/字体// Theme.qml pragma Singleton import QtQuick QtObject { readonly property color primary: #3d5a80 readonly property color primaryDark: #1d3557 readonly property color accent: #e63946 readonly property color bg: #f0f4f8 readonly property color textPrimary: #2c3e50 readonly property int fontSizeBase: 14 }qmldir 中声明 Singleton使用时import . Rectangle { color: Theme.primary } Text { color: Theme.textPrimary; font.pixelSize: Theme.fontSizeBase }7. 数据模型选择决策表场景推荐静态少量数据50JS 数组 / 内联 ListModel中等量可增删数百ListModel海量数据万C QAbstractListModel表格C QAbstractTableModel TableView树TreeViewQt6.4/ C QAbstractItemModel实时数据流C 模型 信号增量更新本地 XMLXmlListModel旧或 C 解析数据库C 模型包 SQL 查询04 章经验QML 侧 ListModel 超过几千条就明显变慢每次修改全量通知数据量大的业务模型必须放 C。8. 综合示例可复用的标签云 列表组件// TagCloud.qml import QtQuick Flow { id: root spacing: 6 property var tags: [] // 外部传入标签数组 property color tagColor: #457b9d signal tagClicked(string tag) Repeater { model: root.tags delegate: Rectangle { width: tagText.implicitWidth 24 height: 28 radius: 14 color: root.tagColor Text { id: tagText anchors.centerIn: parent text: modelData color: white font.pixelSize: 12 } MouseArea { anchors.fill: parent onClicked: root.tagClicked(modelData) } } } }// 使用 TagCloud { tags: [Qt, QML, C, 动画, 布局] tagColor: #2a9d8f onTagClicked: console.log(选中标签, tag) }9. 本章小结MVCModel 提供数据、View 负责滚动/布局、Delegate 渲染每项。ListView 是核心虚拟化、highlight、currentIndex、增删改自动刷新。大数据必须用 C 模型QML 侧模型适合中小数据。Component 独立 .qml 文件实现复用property/signal/alias 定义对外 API。样式Controls 2 风格体系 background/contentItem 定制 主题单例。10. 自测题ListView 为什么能滚动百万条数据reuseItems: true 后 Component.onCompleted 还可靠吗modelData 和 name字段名在 delegate 中分别什么时候用property alias 能转发绑定表达式吗什么时候应该把模型从 QML 挪到 C答案见正文。