05-1_Qt 5.9 C++开发指南_Model/View结构基础(基本原理;数据模型;试图组件;代理)

news2024/11/29 6:28:02

Model/View(模型/视图) 结构是 Qt 中用界面组件显示与编辑数据的一种结构,视图 (View)是显示和编辑数据的界面组件,模型 (Model) 是视图与原始数据之间的接口。Model/View 结构的典型应用是在数据库应用程序中,例如数据库中的一个数据表可以在一个 OTableView 组件中显示和编辑。
主要的视图组件有 QListView、QTreeView 和 QTableView,第 4 章介绍的 QListWidget、QTreeWidget 和 QTableWidget 分别是这 3 个类的便利类,它们不使用数据模型,而是将数据直接存储在组件的每个项里。

本章介绍 Model/View 结构原理,包括 QListView、QTreeView、QTableView 视图组件,以及QStringListModel、OStandardItemModel 等模型类的用法。

Qt中的模型/视图简介和使用(Model/view Programming)是一种框架模式,优点:

  • 在处理较大的数据集时每个组件各司其职,不至于降低性能;
  • 一个Model可以映射到多个view,这样可以以不同的方式查看数据同一份数据;
  • 如果底层数据源的存储改变了,我们只需要处理Model就可以了

文章目录

  • 1 Model/View基本原理
  • 2 数据模型
  • 3 视图组件
  • 4 代理
  • 5 Model/View结构的一些概念
    • 5.1 Model/View的基本结构
    • 5.2 模型索引
    • 5.3 行号和列号
    • 5.4 父项
    • 5.5 项的角色

1 Model/View基本原理

GUI 应用程序的一个很重要的功能是由用户在界面上编辑和修改数据,典型的如数据库应用程序。数据库应用程序中,用户在界面上执行各种操作,实际上是修改了界面组件所关联的数据库内的数据。

将界面组件与所编辑的数据分离开来,又通过数据源的方式连接起来,是处理界面与数据的一种较好的方式。Qt 使用 Model/View 结构来处理这种关系,Model/View 的基本结构如下图 所示。其中各部分的功能如下。

在这里插入图片描述

  • 数据 (Data)是实际的数据,如数据库的一个数据表或 SQL查询结果,内存中的一个 StringList,或磁盘文件结构等
  • 视图或视图组件 (View) 是屏幕上的界面组件,视图从数据模型获得每个数据项的模型索引 (model index),通过模型索引获取数据,然后为界面组件提供显示数据(当只是显示时不需要代理)。Qt 提供一些现成的数据视图组件,如QListView、QTreeView 和QTableView 等
  • 模型或数据模型 (Model) 与实际数据通信,并为视图组件提供数据接口。它从原始数据提取需要的内容,用于视图组件进行显示和编辑。Qt 中有一些预定义的数据模型,如QStringListModel 可作为 StringList 的数据模型,QSglTableModel 可以作为数据库中一个数据表的数据模型。

由于数据源与显示界面通过 Model/View 结构分离开来,因此可以将一个数据模型在不同的视图中显示,也可以在不修改数据模型的情况下,设计特殊的视图组件。

  • 在 Model/View 结构中,还提供了代理 (Delegate) 功能,代理功能可以让用户定制数据的界面显示和编辑方式。(当需要显示和编辑时就需要代理)在标准的视图组件中,代理功能显示一个数据,当数据被编辑时,代理通过模型索引与数据模型通信,并为编辑数据提供一个编辑器,一般是一个QLineEdit 组件。

模型、视图和代理之间使用信号和槽通信。当源数据发生变化时,数据模型发射信号通知视图组件;当用户在界面上操作数据时,视图组件发射信号表示这些操作信息;当编辑数据时,代理发射信号告知数据模型和视图组件编辑器的状态。

2 数据模型

所有的基于项数据(item data) 的数据模型 (Model) 都是基于 QAbstractItemModel 类的,这个类定义了视图组件和代理存取数据的接口。数据无需存储在数据模型里,数据可以是其他类、文件、数据库或任何数据源。Qt 中与数据模型相关的几个主要的类的层次结构如下图 所示。

在这里插入图片描述

图 中的抽象类是不能直接使用的,需要由子类继承来实现一些纯虚函数。Qt 提供了一些模型类用于项数据处理,常见的几个见下表。

在这里插入图片描述

数据库的3个模型将在后期进行介绍,如果现有的模型类无法满足需求,可以从QAbstractItemModel、QAbstractListModel或 QAbstractTableModel 继承,生成自己定制的数据模型类。

3 视图组件

视图组件 (View)就是显示数据模型的数据的界面组件,Qt 提供的视图组件如下。

  • QListView:用于显示单列的列表数据,适用于一维数据的操作。
  • QTreeView:用于显示树状结构数据,适用于树状结构数据的操作。
  • QTableView:用于显示表格状数据,适用于二维表格型数据的操作。
  • QColumnView:用多个 QListView 显示树状层次结构,树状结构的一层用一个 OListView显示。
  • QHeaderView:提供行表头或列表头的视图组件,如 QTableView 的行表头和列表头。

视图组件在显示数据时,只需调用视图类的 setModel()函数,为视图组件设置一个数据模型就可以实现视图组件与数据模型之间的关联,在视图组件上的修改将自动保存到关联的数据模型里,一个数据模型可以同时在多个视图组件里显示数据。

前面介绍了QListWidget、QTreeWidget 和 QtableWidget 3 个可用于数据编辑的组件。这3个类称为便利类(convenience classes),它们分别是3 个视图类的子类,其层次关系如下图 所示

在这里插入图片描述

用于Model/View结构的几个视图类直接从QAbstractItemView 继承而来,而便利类则从相应的视图类继承而来。

视图组件类的数据采用单独的数据模型,视图组件不存储数据。便利类则为组件的每个节点或单元格创建一个项(item),用项存储数据、格式设置等。所以,便利类没有数据模型,它实际上是用项的方式集成了数据模型的功能,这样就将界面与数据绑定了。所以,便利类缺乏对大型数据源进行灵活处理的能力,适用于小型数据的显示和编辑。

4 代理

代理(Delegate)就是在视图组件上为编辑数据提供编辑器,如在表格组件中编辑一个单元格的数据时,缺省是使用一个 QLineEdit 编辑框。代理负责从数据模型获取相应的数据,然后显示在编辑器里,修改数据后,又将其保存到数据模型中。
QAbstractItemDelegate 是所有代理类的基类,作为抽象类,它不能直接使用。它的一个子类QStyledItemDelegate,是 Qt 的视图组件缺省使用的代理类。

对于一些特殊的数据编辑需求,例如只允许输入整型数,使用一个 QSpinBox 作为代理组件更恰当,从列表中选择数据时使用一个 QComhoBox 作为代理组件更好。这时,就可以从QStyledItemDelegate 继承创建自定义代理类。

5 Model/View结构的一些概念

5.1 Model/View的基本结构

在 Model/View 结构中,数据模型为视图组件和代理提供存取数据的标准接口。在 Qt 中,所有的数据模型类都从 QAbstractItemModel 继承而来,不管底层的数据结构是如何组织数据的,QAbstractItemModel 的子类都以表格的层次结构表示数据,视图组件通过这种规则来存取模型中的数据,但是表现给用户的形式不一样。
下图是数据模型的 3 种常见表现形式。不管数据模型的表现形式是怎么样的,数据模型中存储数据的基本单元都是项(item),每个项有一个行号、一个列号,还有一个父项(parent item)。在列表和表格模式下,所有的项都有一个相同的顶层项 (root item): 在树状结构中,行号、列号、父项稍微复杂一点,但是由这 3 个参数完全可以定义一个项的位置,从而存取项的数据。

在这里插入图片描述

5.2 模型索引

为了保证数据的表示与数据存取方式隔离,数据模型中引入了模型索引 (model index)的概念。通过数据模型存取的每个数据都有一个模型索引,视图组件和代理都通过模型索引来获取数据。
OModelIndex 表示模型索引的类。模型索引提供数据存取的一个临时指针,用于通过数据模型提取或修改数据。因为模型内部组织数据的结构随时可能改变,所以模型索引是临时的。如果需要使用持久性的模型索引,则要使用OPersistentModelIndex 类。

5.3 行号和列号

数据模型的基本形式是用行和列定义的表格数据,但这并不意味着底层的数据是用二维数组存储的,使用行和列只是为了组件之间交互方便的一种规定。通过模型索引的行号和列号就可以存取数据。

要获得一个模型索引,必须提供 3 个参数:行号、列号、父项的模型索引。例如,对于上图中的Table Model中的3 个数据项A、B、C,获取其模型索引的代码是:

QModelIndex indexA = model->index(00QModelIndex());
QModelIndex indexB = model->index(11QModelIndex());
OModelIndex indexC = model->index(21QModelIndex());

在创建模型索引的函数中需要传递行号、列号和父项的模型索引。对于列表和表格模式的数据模型,顶层节点总是用 QModelIndex()表示。

5.4 父项

当数据模型是列表或表格时,使用行号、列号存储数据比较直观,所有数据项的父项(parent item)就是顶层项;当数据模型是树状结构时,情况比较复杂(树状结构中,项一般习惯于称为节点),一个节点可以有父节点,也可以是其他节点的父节点,在构造数据项的模型索引时,必须指定正确的行号、列号和父节点。

上图中的Tree Model,节点A 和节点 C的父节点是顶层节点,获取模型索引的代码是:

QModelIndex indexA = model->index(00OModelIndex());
OModelIndex indexC = model->index(21QModelIndex());

但是,节点 B 的父节点是节点 A,节点 B 的模型索引由下面的代码生成:

QModelIndex indexB = model->index(10,indexA);

5.5 项的角色

在为数据模型的一个项设置数据时,可以赋予其不同项的角色 (item role) 的数据。例如,数据模型类QStandardItemModel 的项数据类是 QStandardItem,其设置数据的函数是:

void QStandardItem::setData(const QVariant &value,int role= Qt::UserRole + 1)

其中,value 是需要设置的数据,role 是设置数据的角色。一个项可以有不同角色的数据,用于不同的场合。

role 是 Qt:ItemDataRole 枚举类型,有多种取值,如 Qt:DisplayRole 角色是在视图组件中显示的字符串,Qt:ToolTipRole 是鼠标提示消息,Qt.:UserRole 可以自定义数据。项的标准角色是Ot::DisplayRole。

在获取一个项的数据时也需要指定角色,以获取不同角色的数据。

QVariant QStandardItem::data(int role = Qt::UserRole + 1) const

为一个项的不同角色定义数据,可以告知视图组件和代理组件如何显示数据。例如,在下图中,项的 DisplayRole 数据是显示的字符串,DecorationRole 是用于装饰显示的属性,TolTipRole定义了鼠标提示信息。不同的视图组件对各种角色数据的解释和显示可能不一样,也可能忽略某些角色的数据。

在这里插入图片描述

前面已经介绍了便利类 QListWidget、QTreeWidget 和 QTableWidget 的使用,后面的文章将介绍 Model/View 结构的基本用法,包括 Qt 预定义的 QstringListModel、OFileSystemModel、OStandardItemModel以及视图组件 QListView、QTableView、QTreeView的使用,还介绍如何设计和使用自定义代理。涉及数据库的 Mode/View 的使用将在数据库一章单独介绍。

6. 比较好的Model/View简介视频:Qt 16: 模型/视图简介和使用 (Model/View Programming);Qt 17:模型/视图编程实例 (Model/View Programming)(未看);Qt 18 : 模型视图编程实例(未看),视频博主博客地址

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何使用ArcGIS Pro制作一张天府机场区位图

ArcGIS系列产品的重要功能之一就是制图,相较于ArcGIS, ArcGIS Pro在制图这块有很大的改进,用户可以连接上ArcGIS Online丰富的在线资源,感受到ArcGIS Pro强大的制图能力,但是在开始的时候可能会有些不习惯,因为在操作上…

C#在工业自动化领域的应用前景如何?

在2021年,C#与工业自动化已经开始结合,并且这种趋势有望在未来继续发展。C#是一种功能强大的编程语言,其面向对象的特性、跨平台支持以及丰富的类库和工具,使其成为在工业自动化领域应用的有力工具。 我这里刚好有嵌入式、单片机…

【每天40分钟,我们一起用50天刷完 (剑指Offer)】第三十天 30/50 连续子数组的最大和【dp】

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客,如有问题交流,欢迎评论区留言,一定尽快回复!(大家可以去看我的专栏,是所有文章的目录)   文章字体风格: 红色文字表示&#…

断点续传技术在工业边缘网关HiWoo Box中的价值

引言 工业边缘计算是近年来迅速发展的一项重要技术,它将数据处理和分析功能推向了设备和传感器的边缘,从而大大提高了工业自动化系统的效率和可靠性。然而,工业现场环境复杂多变,网络稳定性不足常常导致数据传输中断,…

TPS61021A 具有 0.5V 超低输入电压的3A升压转换器

1 特性 1 • 输入电压范围:0.5V至4.4V • 启动时的最小输入电压为0.9V • 可设置的输出电压范围:1.8V到4.0V • 效率高达91%(VIN2.4V、VOUT3.3V 且IOUT 1.5A 时) • 2.0MHz 开关频率 • IOUT > 1.5A,VOUT 3.…

Java 的异常体系

一个思维导图回顾一下 Java 的异常体系。 ​ 上面的图片没有罗列出所有的异常类型,但也基本概括了 Java 异常的继承体系。所有的异常类都继承自 Throwable ,Throwable 有两个直接子类 Error 和 Exception 。 Exception 一般指可以/应该捕获和处理的异常…

php代码逻辑题

<?php error_reporting(0); show_source(__FILE__); $guess $_POST[guess]; $data (array)json_decode($_GET[data]); if(substr(md5($guess),0,27)797ed5077436dc8abaec64750e2)if ($data[aaa] !666 && intval($data[aaa],0) 666 &‮⁦!!⁩⁦& "h…

DPDK:如何查看dpdk版本

背景 服务器上曾经装过很多版本的dpdk&#xff0c;此时如果编译某个程序出现奇怪错误的时候不由得会怀疑是不是dpdk版本的问题。。。 令人吃惊的是&#xff0c;网上搜了一圈居然没有一个简单直接的方法能够直接使用&#xff0c;于是自己实验了一下摸索出来一个方法。 较新版本的…

企业设备报修管理系统你nodejs+vue

S模式系统&#xff0c;采用vue框架&#xff0c;MYSQL数据库设计开发&#xff0c;充分保证系统的稳定性。系统具有界面清晰、操作简单&#xff0c;功能齐全的特点&#xff0c;使得中小企业设备管理系统管理工作系统化、规范化。本系统的使用使管理人员从繁重的工作中解脱出来&am…

GFLv1 论文学习

1. 解决了什么问题&#xff1f; 单阶段目标检测器通过密集预测的方式进行分类、定位。分类一般使用 Focal Loss&#xff0c;而边框回归则通过 Dirac delta 分布来学习。近年来的改进方向是引入一个单独的分支&#xff0c;预测定位的质量&#xff0c;然后用该质量分数去辅助分类…

Mediabox:年度最佳音视频开发工具

“2023稀土开发者大会”落下帷幕&#xff0c;由稀土掘金社区评选的的掘金技术引力榜重磅出炉&#xff0c;共有22个优秀实践案例上榜&#xff0c;涵盖对技术行业发展有特别贡献的人物、开发工具、开源项目、技术团队和技术方案。其中&#xff0c;阿里云视频云「MediaBox」突出重…

新手杯— 天知地知

0x00 前言 CTF 加解密合集&#xff1a;CTF 加解密合集 0x01 题目 好不容易要到了妹子手机号&#xff0c;却是加密的&#xff0c;怎么办&#xff0c;兄弟们很急&#xff0c;在线等&#xff01;听说妹子是佛山的 加密后的手机号&#xff1a;(86)981935301754格式ctfshow{妹子手…

Redis 7.0.12发布,进行了安全和错误修复

导读Redis 7.0.12发布&#xff0c;进行了安全修复和错误修复。 升级紧迫性 安全性&#xff1a;请参阅下面的安全修复。 安全修复 (CVE-2022-24834)在Redis中执行特制的Lua脚本可能会在cjson和cmsgpack库中触发堆溢出。堆溢出&#xff0c;導致堆損毀及可能的遠端執行程式碼。導…

排序算法 - 快速排序(4种方法实现)

快速排序 快速排序是啥&#xff1f;三数取中&#xff1a;1.挖坑法&#xff08;推荐掌握&#xff09;2.前后指针法&#xff08;推荐掌握&#xff09;3.左右指针法&#xff08;霍尔版本&#xff09;&#xff08;容易出错&#xff09;4.非递归实现 本篇文章的源代码在这&#xff0…

解放研究者:GPT自动化科研

GPT Researcher 是一个自主代理程序&#xff0c;旨在进行多种任务的全面在线研究。 该代理能够生成详细、事实性和公正的研究报告&#xff0c;并提供个性化选项&#xff0c;以便关注相关资源、大纲和教训。受到AutoGPT和最近的Plan-and-Solve论文的启发&#xff0c;GPT Researc…

macd底背离画线指标公式

使用说明&#xff1a; MACD底背离是一种可能预示着价格反转的信号&#xff0c;尤其在价格走势出现下跌趋势时&#xff0c;它可以提供一定程度的参考。然而&#xff0c;作为任何技术指标一样&#xff0c;MACD底背离并不是绝对准确的&#xff0c;可能会产生误导性信号。因此&…

Inno Setup打包winform、wpf程序可判断VC++和.net环境

Inno Setup打包winform、wpf程序可判断VC和.net环境 1、下载Inno Setup2、新建打包文件、开始打包1、新建打包文件2、填写 应用名称、版本号、公司名称、公司官网3、选择安装路径 Custom是指定默认路径、Program Files folder是默认C盘根目录4、选择程序启动exe文件 以及Addfol…

stable diffusion webui mov2mov

手把手教你用stable diffusion绘画ai插件mov2mov生成动画_哔哩哔哩_bilibili手把手教你用stable diffusion绘画ai插件mov2mov生成动画, 视频播放量 14552、弹幕量 3、点赞数 275、投硬币枚数 114、收藏人数 980、转发人数 75, 视频作者 懂你的冷兮, 作者简介 科技改变世界&…

I2S 总线接口

I2S(Inter-IC Sound)总线有时候也写作IIS&#xff0c;I2S是飞利浦公司提出的一种用于数字音频设备之间进行音频数据传输的总线。和I2C、SPI这些常见的通信协议一样&#xff0c;I2S总线用于主控制器和音频CODEC芯片之间传输音频数据。因此&#xff0c;要想使用I2S协议&#xff0…

C#基础--进程和线程的认识

C#基础–进程和线程的认识 一、基础概念 1. 什么是进程? 进程并不是物理的东西,是虚拟出来的,是一种概念。当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。而一个进程又是由多个线程所组成的。是一种计算机概念,是程序在运…