QML模型基础架构

QML采用经典的Model-View-Delegate (MVD)​架构来分离数据与界面,这与MVC模式类似但更加适合声明式UI开发。在这个架构中:

  • Model​:负责管理数据,可以是简单的整数,也可以是复杂的C++自定义模型
  • View​:负责显示数据,如ListView、GridView、TableView等
  • Delegate​:负责如何显示单个数据项,相当于模板
// 基本结构示例
ListView {width: 200; height: 250model: myModel  // 数据模型delegate: Rectangle {  // 委托项Text { text: model.display }}
}

Qt的模型系统最大的特点是灵活性——几乎任何数据类型都可以作为模型使用。模型在QML中不仅是数据容器,还通过角色(roles)​系统提供数据访问接口,委托可以通过这些角色访问模型中的数据项。

整数模型:最简单的模型类型

整数模型是QML中最简单的模型形式,它仅提供一个整数计数,用于生成重复的UI元素。

import QtQuick 2.15
import QtQuick.Controls 2.15Rectangle {width: 600; height: 400ListView {anchors.fill: parentmodel: 5  // 整数作为模型delegate: Rectangle {width: parent.widthheight: 30required property int indexText {text: "我是第"+index + "个元素"}}}
}

使用场景​:

  • 创建固定数量的相似组件
  • 快速原型开发
  • 不需要复杂数据绑定的简单界面

特点​:

  • 每个委托项自动获得index属性(从0开始)
  • 没有额外的数据角色,仅提供索引值
  • 性能高效,适合静态简单布局

高级用法​:
可以与Repeater结合使用,创建网格布局:

Grid {columns: 3Repeater {model: 9  // 创建3x3网格Rectangle {width: 50; height: 50color: index%2 ? "red" : "blue"}}
}

整数模型虽然简单,但在许多不需要复杂数据的场景下非常实用,能够避免创建不必要的复杂模型,注意:整数模型中的项目数量不能超过100000000

列表模型ListModel:动态数据管理

ListModel是QML中最常用的模型之一,它允许在QML中直接定义结构化数据,并支持动态修改。

基本用法

import QtQuick 2.0ListModel {id: fruitModelListElement {name: "Apple"cost: 2.45}ListElement {name: "Orange"cost: 3.25}
}

在视图中使用:

ListView {anchors.fill: parentmodel: fruitModeldelegate: Row {Text { text: "名称:" + name }Text { text: "价格:" + cost }}
}

ListElement特性​:

  • 必须以小写字母开头
  • 值只能是简单类型:字符串、布尔值、数字或枚举值
  • 支持嵌套ListElement,创建层次结构

动态操作

ListModel提供了一系列方法用于动态修改数据:

// 添加数据
fruitModel.append({"name": "Banana", "cost": 1.95})// 插入数据
fruitModel.insert(1, {"name": "Pear", "cost": 3.50})// 修改数据
fruitModel.set(0, {"name": "Pineapple", "cost": 2.75})// 移动数据
fruitModel.move(0, 2, 1)  // 将第0项移动到第2项// 删除数据
fruitModel.remove(1)  // 删除第1项// 清空模型
fruitModel.clear()

高级特性

动态角色​:ListModel支持动态添加角色,只需设置dynamic属性为true:

ListModel {id: dynamicModeldynamic: true// 可以后续添加新角色
}Component.onCompleted: {dynamicModel.append({"newRole": "value"})
}

与WorkerScript配合​:对于大数据量操作,可以在后台线程处理模型以避免界面卡顿:

WorkerScript {id: workersource: "script.mjs"
}Timer {id: timerinterval: 2000; repeat: truerunning: trueonTriggered: {var msg = {'action': 'appendCurrentTime', 'model': listModel};worker.sendMessage(msg);}
}

ListModel非常适合中等规模的数据集,它提供了QML中直接操作数据的便利性,但对于大规模数据复杂数据结构,建议使用C++实现的模型。

对象模型ObjectModel:封装可视化项

ObjectModel是一种特殊模型,它直接包含可视化项而不是数据,因此不需要委托(delegate)。

基本用法

import QtQuick 2.12
import QtQml.Models 2.12ObjectModel {id: itemModelRectangle { height: 30; width: 80; color: "red" }Rectangle { height: 30; width: 80; color: "green" }Rectangle { height: 30; width: 80; color: "blue" }
}ListView {anchors.fill: parentmodel: itemModel
}

特点​:

  • 模型项本身就是可视化组件
  • 不需要定义delegate
  • 适合固定数量有限的可视化项集合
  • 性能优于Repeater生成的相同数量项

动态操作

ObjectModel也支持动态修改内容:

// 添加项
itemModel.append(rectComponent.createObject())// 插入项
itemModel.insert(1, textComponent.createObject())// 移动项
itemModel.move(0, itemModel.count-1, 1)// 删除项
itemModel.remove(0)// 获取项
var item = itemModel.get(2)

与C++集成

ObjectModel也可以从C++端创建和管理:

class ObjectModel : public QObject {Q_OBJECT
public:Q_INVOKABLE QVariant _objmodel() {return QVariant::fromValue(objmodellist);}// 其他操作接口...
private:QList<QObject*> objmodellist;
};

在QML中使用:

ListView {delegate: Text { text: model.modelData.data }model: Global._objmodel()
}

ObjectModel非常适合混合布局场景,其中某些项需要特殊定制而不是统一的数据驱动委托。

表格模型TableModel:处理二维数据

TableModel用于处理表格数据,相比ListModel,它增加了列的概念,适合展示类似数据库表格的结构化数据。

QML实现

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQml.Models 2.15TableView {anchors.fill: parentcolumnSpacing: 1rowSpacing: 1model: TableModel {TableModelColumn { display: "name" }TableModelColumn { display: "age" }rows: [{"name": "Alice","age": 22},{"name": "Bob","age": 25}]}delegate: Rectangle {Text { text: display }}
}

C++实现

对于更复杂的表格,通常需要在C++中实现:

class DataModel : public QAbstractTableModel {Q_OBJECT
public:int rowCount(const QModelIndex&) const override {return m_data.size();}int columnCount(const QModelIndex&) const override {return m_roleList.size();}QVariant data(const QModelIndex &index, int role) const override {return m_data[index.row()].at(index.column());}QHash<int, QByteArray> roleNames() const override {QHash<int, QByteArray> roles;for(int i=0; i<m_roleList.size(); i++) {roles[Qt::UserRole+i+1] = m_roleList.at(i).toLocal8Bit();}return roles;}
private:QList<QVariantList> m_data;QStringList m_roleList;
};

注册到QML:

qmlRegisterType<DataModel>("CustomModels", 1, 0, "DataModel");

高级特性

动态列管理​:可以通过动态添加TableModelColumn来创建灵活的表结构

行选择​:配合SelectionModel实现行选择功能

排序​:通过实现sort函数添加排序能力

性能优化​:对于大型表格,需要实现fetchMore/canFetchMore进行分批加载

TableModel特别适合展示业务数据,如数据库查询结果、电子表格等结构化信息。

XML列表模型XmlListModel:处理XML数据 使用较少

XmlListModel专门用于解析和展示XML格式的数据,常见于RSS阅读器或Web API交互场景。

基本用法

import QtQuick 2.0
import QtQuick.XmlListModel 2.0XmlListModel {id: xmlModelsource: "http://www.example.com/feed.xml"query: "/rss/channel/item"XmlRole { name: "title"; query: "title/string()" }XmlRole { name: "pubDate"; query: "pubDate/string()" }
}ListView {width: 180; height: 300model: xmlModeldelegate: Text { text: title + ": " + pubDate }
}

关键属性​:

  • source:XML数据源,可以是本地文件或网络URL
  • query:XPath表达式,指定要处理的节点集
  • XmlRole:定义如何从XML节点提取数据
  • namespaceDeclarations:处理含命名空间的XML

动态查询

XmlListModel支持动态修改查询条件:

// 只获取特定条件的项目
xmlModel.query = "/rss/channel/item[contains(title, 'Qt')]"// 重新加载模型
xmlModel.reload()

错误处理

通过status属性处理加载状态:

Text {text: {switch(xmlModel.status) {case XmlListModel.Loading: return "加载中...";case XmlListModel.Ready: return "就绪";case XmlListModel.Error: return "错误: "+xmlModel.errorString();}}
}

性能考虑

  • 大型XML文件考虑在后台线程解析
  • 使用progress属性显示加载进度
  • 合理设置XPath查询,避免复杂查询影响性能

XmlListModel极大简化了XML数据处理流程,是构建RSS阅读器或与Web服务交互的理想选择。

Package机制:多视图共享委托--使用较少

Package(包)机制允许多个视图共享同一组委托实例,实现复杂的视图交互效果。

基本概念

Package与DelegateModel配合使用,可以:

  • 在不同视图中复用同一委托
  • 实现项目在不同视图间动画过渡
  • 构建主从视图(Master-Detail)布局

实现示例

import QtQuick 2.12
import QtQml.Models 2.12
import Qt.labs.qmlmodels 1.0DelegateModel {id: visualModelmodel: ListModel {ListElement { name: "Item 1"; color: "red" }ListElement { name: "Item 2"; color: "green" }}delegate: Package {Item { Package.name: "list" }Item { Package.name: "grid" }Rectangle {width: parent.width; height: 50color: model.colorText { text: model.name }parent: viewSwitcher.checked ? grid : list}}
}ListView {width: 200; height: 300model: visualModel.parts.list
}GridView {x: 210; width: 300; height: 300model: visualModel.parts.grid
}

Package机制为构建复杂视图交互提供了强大支持,是QML模型系统中较高级但极具价值的功能。

模型性能优化与实践建议

在实际项目中使用QML模型时,​性能可维护性是需要重点考虑的因素。

性能优化技巧

  1. 虚拟化​:ListView/GridView等视图默认只创建可见项委托,确保clip属性为true

  2. 轻量委托​:保持委托尽可能简单,复杂委托会显著影响滚动性能

  3. 批处理操作​:对于大规模数据修改,先调用beginResetModel(),修改完成后调用endResetModel()

  4. C++模型​:数据量超过1000项时考虑使用C++实现的模型

  5. 缓存策略​:对于网络数据或计算成本高的模型,实现缓存机制

模型选择指南

模型类型适用场景优点缺点
整数模型简单重复项极简、高效无数据绑定
ListModel中小型动态数据QML内定义、易用大数据性能差
ObjectModel固定可视化项无需委托、灵活不适合数据驱动
TableModel表格数据行列结构、功能丰富复杂度高
XmlListModelXML数据内置解析、XPath支持仅只读
C++模型大型专业应用高性能、功能全面需要C++知识

常见问题解决

数据不同步​:确保模型变更时发出正确的信号(如dataChanged)

内存泄漏​:ObjectModel中注意管理QObject生命周期

跨线程访问​:使用WorkerScript处理耗时操作

复杂过滤​:考虑使用SortFilterProxyModel等中间模型

最佳实践

  1. 角色命名​:使用有意义的角色名而非简单role1、role2

  2. 模块化​:将复杂模型分离到单独QML文件或C++类中

  3. 测试​:大数据量下测试滚动性能和内存占用

  4. 文档​:为自定义模型编写使用说明,特别是角色定义

  5. 渐进增强​:简单需求先用ListModel,复杂时再迁移到C++模型

结语

QML的模型系统提供了从简单到复杂、从纯QML到C++集成的全方位解决方案。掌握这些模型类型的特点和使用场景,能够帮助开发者构建数据驱动的高性能用户界面。无论是简单的整数模型还是复杂的C++集成模型,Qt都提供了相应的工具和模式,关键在于根据项目需求选择合适的工具

随着Qt的持续发展,QML的模型系统也在不断进化,如最新的Qt 6中引入的DelegateChooser等新特性,进一步增强了模型的灵活性。建议开发者定期查阅Qt官方文档,了解最新的最佳实践和功能增强。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/90404.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/90404.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/90404.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Trae IDE与MCP实现网页自动化测试的最佳实践

引言 在现代Web开发流程中&#xff0c;自动化测试已成为保障应用质量、提升开发效率的关键环节。Playwright作为一款新兴的测试框架&#xff0c;因其出色的跨浏览器支持能力和丰富的API特性&#xff0c;正逐渐成为自动化测试领域的主流选择。本文将详细介绍如何在葡萄城Trae ID…

Android 动画优化

动画是提升 Android 应用用户体验的核心手段 —— 流畅的过渡动画能让页面切换更自然&#xff0c;交互反馈动画能让操作更有质感。但动画也是性能 “重灾区”&#xff1a;掉帧、卡顿、内存暴涨等问题&#xff0c;往往源于对动画原理和优化技巧的忽视。本文将从动画性能的核心瓶…

Linux——进程间通信,匿名管道,进程池

文章目录一、进程间通信&#xff08;IPC&#xff09;的理解1.为什么进程间要通信&#xff08;IPC&#xff09;2.如何进行通信二、匿名管道1.管道的理解2.匿名管道的使用3.管道的五种特性4.管道的四种通信情况5.管道缓冲区容量三、进程池1.进程池的理解2.进程池的制作四、源码Pr…

深度分析Java内存回收机制

内存回收机制是Java区别于C/C等语言的核心特性之一&#xff0c;也是Java开发者理解程序性能、解决内存相关问题&#xff08;如内存泄漏、OOM&#xff09;的关键。 核心目标&#xff1a; 自动回收程序中不再使用的对象所占用的内存&#xff0c;防止内存耗尽&#xff0c;同时尽量…

uniapp “requestPayment:fail [payment支付宝:62009]未知错误“

解决方案&#xff1a;兄弟&#xff0c;有一种可能是你用测试机没有安装支付宝

分布在内侧内嗅皮层(MEC)的带状细胞对NLP中的深层语义分析的积极影响和启示

带状细胞&#xff08;Band Cells&#xff09;作为内侧内嗅皮层&#xff08;Medial Entorhinal Cortex, MEC&#xff09;层Ⅱ/Ⅲ的核心空间编码单元&#xff08;如网格细胞、头方向细胞等&#xff09;&#xff0c;其独特的神经计算机制为自然语言处理&#xff08;NLP&#xff09…

综合实验(4)

文章目录 目录 文章目录 前言 实验配置 实验总结 总结 前言 Cisco IOS Site-to-Site VPN&#xff08;虚拟专用网络&#xff09;是一种通过公共网络&#xff08;如互联网&#xff09;建立安全连接的技术&#xff0c;使不同地理位置的局域网&#xff08;LAN&#xff09;能够安…

JavaSE:开发环境的搭建(Eclipse)

一、IDE概述与核心价值 集成开发环境定义 提供编译器、调试器、项目管理工具的统一平台&#xff0c;显著提升开发效率。 Eclipse核心优势&#xff1a; 免费开源 &#xff1a;社区驱动&#xff0c;无授权费用跨平台支持 &#xff1a;Windows/Linux/macOS全兼容多语言扩展 &a…

使用LLaMA-Factory对大模型进行微调

之前了解过一些LLM从训练到落地的过程; 其中一个重要的步骤就是微调; 预训练&#xff1a;在大规模数据上学习通用语言知识。(使用海量无标注文本&#xff08;TB级&#xff09;) 微调&#xff1a;在预训练基础上&#xff0c;使用特定任务的标注数据进一步优化模型。(使用少量任务…

WxPython——一些最常见的错误现象及解决方法

一些最常见的错误现象及解决方法 有一些错误它们可能会发生在你的wxPython应用程序对象或初始的顶级窗口在创建时&#xff0c;这些错误可能是很难诊断的。下面我们列出一些最常见的错误现象及解决方法&#xff1a; 错误现象&#xff1a;程序启动时提示“unable to import modul…

SparkSQL 子查询 IN/NOT IN 对 NULL 值的处理

SparkSQL 子查询 IN/NOT IN 对 NULL 值的处理 官网&#xff1a;https://spark.apache.org/docs/4.0.0/sql-ref-functions.html https://spark.apache.org/docs/4.0.0/sql-ref-null-semantics.html#innot-in-subquery Unlike the EXISTS expression, IN expression can return…

【安卓笔记】lifecycle与viewModel

0. 环境&#xff1a; 电脑&#xff1a;Windows10 Android Studio: 2024.3.2 编程语言: Java Gradle version&#xff1a;8.11.1 Compile Sdk Version&#xff1a;35 Java 版本&#xff1a;Java11 1. 本篇文章涉及到的内容 lifecycle livedata databinding viewModel 2. …

84、逆向工程开发方法

逆向工程开发方法是一种通过分析现有产品、系统或代码来理解其设计原理、功能实现及潜在缺陷&#xff0c;并在此基础上进行改进、复制或创新的技术过程。它广泛应用于软件、硬件、机械、电子等多个领域&#xff0c;尤其在缺乏原始设计文档或需要快速掌握复杂系统时具有显著优势…

ospf单区域实验

拓扑图&#xff1a;AR1&#xff1a;[Huawei]ospf 1 router-id 1.1.1.1 [Huawei-ospf-1]area 0[Huawei-ospf-1-area-0.0.0.0]network 192.168.1.0 0.0.0.255&#xff08;1.当前网段会被ospf的进程1学习到然后通告出去&#xff1b;2.如果接口的IP地址处于这个网段中&#xff0c…

Linux命令基础完结篇

用户权限修改 chmod修改文件权限 文字设定法 u&#xff1a;所有者g&#xff1a;所属组o&#xff1a;其他人a&#xff1a;所有&#xff1a;添加权限-&#xff1a;删除权限&#xff1a;赋予权限数字设定法 r&#xff1a;4w&#xff1a;2x&#xff1a;1每一组权限&#xff1a;0~7举…

高效互联,ModbusTCP转EtherCAT网关赋能新能源电缆智能制造

在新能源汽车快速发展的背景下&#xff0c;新能源电缆作为关键组件&#xff0c;需满足耐高低温、阻燃、耐老化等严苛要求&#xff0c;这对生产线的工艺与设备提出了更高标准。为提升制造效率&#xff0c;某领先设备制造商创新采用**ModbusTCP转EtherCAT网关**技术&#xff0c;实…

Java_多线程_生产者消费者模型_互斥锁,阻塞队列

生产者消费者模型(Producer-Consumer Model)是计算机科学中一个经典的并发编程模型&#xff0c;用于解决多线程/多进程环境下的协作问题。 基本概念 生产者&#xff1a;负责生成数据或任务的实体 消费者&#xff1a;负责处理数据或执行任务的实体 缓冲区&#xff1a;生产者与消…

Vue3实现视频播放弹窗组件,支持全屏播放,音量控制,进度条自定义样式,适配浏览器小窗播放,视频大小自适配,缓冲loading,代码复制即用

效果图组件所需VUE3代码<template><div class"video-dialog" :class"fullScreen && video-dialog-full-screen"><el-dialogv-model"props.visible"draggable:show-close"false"title""centeralign-c…

LLM层归一化:γβ与均值方差的协同奥秘

LLM层归一化参数均值和方差;缩放和平移参数是什么 层归一化(Layer Normalization,LN)是深度学习中用于稳定神经网络训练的一种归一化技术 均值和方差参数用于对输入数据进行标准化处理,即将输入数据转换为均值为0、方差为1的标准正态分布 缩放因子γ\gammaγ:标准化后…

智慧场景:定制开发开源AI智能名片S2B2C商城小程序赋能零售新体验

摘要&#xff1a;智慧场景作为零售行业创新发展的关键载体&#xff0c;正深刻改变着消费者的生活方式。本文聚焦智慧零售模式下智慧场景的构建&#xff0c;以定制开发开源AI智能名片S2B2C商城小程序为切入点&#xff0c;深入探讨其在零售企业选址布局、商业模式创新、经营理念转…