首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >Qt5.2模型-视图-模式:如何将底层数据结构的变化通知模型对象

Qt5.2模型-视图-模式:如何将底层数据结构的变化通知模型对象
EN

Stack Overflow用户
提问于 2014-01-31 03:15:40
回答 2查看 5.8K关注 0票数 4

我有一个类,用于永久存储一些以表格方式组织的项目。这个类与Qt完全无关,来自不同的库。让我们为这个问题的其余部分调用这个类DataContainer。它提供了std-c++兼容的迭代器来访问和操作内容。

我需要通过Qt来显示和修改这些数据。我的想法是创建一个类DataContainerQtAdaptor,该类继承自QAbstractTableModel,并存储指向DataContainer对象的指针。DataContainerQtAdaptor充当DataContainer对象的适配器,我的Qt应用程序内部的所有操作都是通过这个适配器完成的。然后我使用一个QTableView小部件来显示信息。

不幸的是,DataContainer可能被线程/进程更改。(例如,将DataContainer看作封装数据库连接的某个C++类,而该数据库可能被其他人更改)。

问题:

1)假设我有一个函数,每次更改DataContainer对象的内部结构时都调用它。必须调用的QAbstractTableModel的正确功能是什么,以通知底层更改的模型?我需要“亲爱的模型,您的持久存储后端更改。请,更新自己,并发出信号给每个附加的视图,以反映这一变化”。

( 2)假设1)解。在通过GUI触发更改时,避免“双”GUI更新的最佳方法是什么?例如:用户单击表小部件->表小部件中的一个单元格,调用模型的setData ->模型将更改推送到后端->后端触发它自己的"onUpdate“函数->模型重新读取完整的后端(尽管它已经知道了更改) -> GUI再次更新。

3)用户应该能够通过GUI插入新的行/列并将数据放入其中。但是位置是由这些数据决定的,因为后端保持数据的排序。因此,我有以下问题:用户决定在末尾创建一个新行,并将新数据推送到后端。当重新读取后端/模型时,数据通常不在最后一个位置,而是插入到中间的某个位置,所有其他数据都已向前移动。我是否将表视图小部件的所有属性保持同步,比如“选择一个单元格”?

我相信,必须有一些简单的标准解决方案来解决所有这些问题,因为它与QFileSystemModel的工作方式相同。用户选择一个文件,其他一些进程创建一个新文件。新文件将显示在视图中,随后的所有行都向前移动。选择也向前推进。

马提亚斯

EN

回答 2

Stack Overflow用户

发布于 2014-01-31 10:46:08

模型语义

首先,您必须确保QAbstractItemModel不能处于不一致的状态。这意味着在对底层数据进行某些更改之前,必须在模型上触发一些信号。

对结构的更改与对数据的更改有根本的区别。结构更改是要添加或删除模型的行/列。数据更改仅影响现有数据项的值。

  • 结构更改需要围绕修改调用beginXxxendXxx。在调用beginXxx之前,不能修改任何结构。当您完成结构更改后,请调用endXxxXxxInsertColumnsMoveColumnsRemoveColumnsInsertRowsMoveRowsRemoveRowsResetModel之一。 如果更改影响到许多不连续的行/列,则表示模型重置成本更低--但要小心,视图上的选择可能无法存活。
  • 保持结构完整的数据更改只要求在底层数据被修改后发送dataChanged。这意味着对data的调用可能会在查询模型的对象接收到dataChanged之前返回一个新值。

这也意味着非常量模型对非QObject类几乎毫无用处,当然,除非您使用观察者或类似的模式实现桥功能。

断续更新环

在模型上处理update循环的Qt-惯用方法是利用项角色。这完全取决于你的模型如何解释角色。QStringListModel实现的一个简单而有用的行为就是将角色从setData调用转发到dataChanged,否则忽略角色。

股票视图小部件只对dataChangedDisplayRole作出反应。然而,当他们编辑数据时,他们用EditRole调用EditRole。这就打破了循环。这种方法既适用于查看小部件,也适用于Qt快速视图项。

将数据插入排序模型

只要模型在完成排序时正确地发出更改信号,您就可以了。

行动顺序如下:

  1. 视图添加一行并调用模型的insertRow方法。模型可以将空行添加到基础容器中,也可以不添加。关键是必须暂时保留空行索引。
  2. 编辑从行中的项开始。视图状态更改为Editing
  3. 编辑在项目上完成。视图退出编辑状态,并设置模型上的数据。
  4. 模型根据项目的内容确定项目的最终位置。
  5. 模型调用beginMoveRows
  6. 模型通过在正确的位置插入项目来更改容器。
  7. 模型调用endMoveRows

在这一点上,一切都如你所料。视图可以自动跟踪被移动的项目,如果它在被移动之前被聚焦。在默认情况下,编辑的项都是集中的,因此工作正常。

必需的容器功能

您的DataContainer没有足够的功能使其工作,除非所有对它的访问都是通过模型完成的。如果您想直接访问容器,那么要么让容器显式继承QAbstractXxxxModel,要么向容器添加通知系统。前者是一个更容易的选择。

您的核心问题归结为:我可以在不实现模型通知API的某些变体的情况下拥有模型功能吗?显而易见的答案是:不,对不起,你不能-从定义上来说。如果您不希望容器是一个QObject,那么您将需要您的模型shim。没有办法可以绕过它。

文件系统通知QFileSystemModel有关已更改的各个目录条目。您的容器也必须这样做--这相当于提供某种形状或形式的dataChanged信号。如果模型中有被移动或添加/删除的项--其结构更改--则必须通过调用相关的xxxAboutToBeYyyendZzz方法来发出beginZzzendZzz信号。

索引

QModelIndex最重要的未得到说明的方面是:它的实例只有在模型的结构没有改变的情况下才有效。如果您的模型通过了一个在结构更改之前生成的索引,您就可以自由地以一种未定义的方式进行操作(崩溃、启动核打击等)。

QModelIndex::internalPointer()存在的全部原因是您有一个底层的、复杂的索引数据容器的用例。模型的createIndex方法的实现必须生成以某种形式存储对DataContainer索引的引用的索引实例。如果这些索引适合指针,则不需要分配堆上的数据。如果需要在堆上分配容器索引存储,则必须保留指向该数据的指针,并在容器的结构更改时随时删除它。您可以自由地这样做,因为在结构更改后,没有人应该使用索引实例。

票数 8
EN

Stack Overflow用户

发布于 2014-01-31 03:47:20

从方法bool QAbstractItemModel::insertRows(int row, int count, const QModelIndex & parent = QModelIndex())的文档

如果您实现自己的模型,如果希望支持插入,则可以重新实现此函数。或者,您可以提供自己的API来修改数据。在这两种情况下,您都需要调用beginInsertRows()和endInsertRows()来通知其他组件模型已经更改。

removeRows()moveRows()也是如此(他们有自己的begin*()end*()方法)。为了修改现有项目的数据,有一个dataChanged()信号。

是这样的(问题1的答案):

实现您自己的插入/删除/修改数据的方法,其中每个方法必须如下所示:

代码语言:javascript
运行
AI代码解释
复制
beginInsertRows(parentIndex, beginRow, endRow);
// code that modifies underlying data
endInsertRows();

必须提供beginRowendRow,以通知将插入哪些行以及其中的行数(endRow- where )。

对于beginDeleteRows()beginMoveRows()来说,情况是一样的。

当您有一个简单地修改现有项中的数据的方法时,该方法必须在末尾发出信号:dataChanged()

如果您对数据进行了大量更改,有时只需在执行此巨大修改的方法中调用beginResetModel()endResetModel()就更简单了。它将导致所有视图刷新其中的所有数据。

对问题2的回答:

这取决于视图类实现,如果它将“双更新”。当您在视图中输入数据时,数据将通过模型中的一个版本方法(insertRows()setData()等)发送到模型。这些方法的默认实现总是使用begin*()end*()方法,因此模型会发出适当的通知信号。所有视图都会监听这些信号,包括输入数据的信号,因此将执行“双更新”。

定义此行为的唯一方法是继承视图并重新实现其受保护的插槽(如dataChanged()和类似的),以避免在检测到该视图提供的值时进行更新。

我不确定Qt视图是否已经这样做了。要想解决这个问题,需要有人在Qt内部有更多的知识,或者研究Qt源代码(我目前还没有)。如果有人知道这一点,请评论,我会更新答案。

我认为从模型中重新加载数据并没有那么糟糕--它保证了您所看到的确实是来自模型的值。您可以避免编辑器和视图错误可能出现的问题。

对问题3的回答:

当你重新加载整个模型,那么就没有简单的方法来跟踪选择。在这种情况下,您需要询问view->selectionModel()当前选择的情况,并在重新加载之后尝试恢复它。

但是,如果您执行部分刷新(使用我在答案1中描述的方法),则视图将为您跟踪所选内容。没什么好担心的。

最后评论:

如果您想编辑来自模型类外部的数据,您可以这样做。只要将begin*()end*()方法公开为公共API,其他编辑数据的代码就可以通知模型和视图更改。

虽然这是可以做到的,但这不是一个好的做法。这可能会导致错误,因为无论您修改数据,都很容易忘记调用通知。如果您必须调用model来通知更改,为什么不将所有编辑代码移到模型内部并公开编辑API呢?

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21478746

复制
相关文章
使用信号监控 Django 模型对象字段值的变化
Django 信号 (Signals) 的功能类似于 WordPress 的动作 (action),用于为项目全局增加事件的广播 (dispatch) 与接收 (receive) 机制。其中,灵活使用其内置的模型信号 (Model Signals) 的接收功能就可以监控大部分模型对象 (Model instances) 的变化。因为不需要修改模型本身的代码,在进行跨应用 (App) 监控时有低耦合的优势。
BigYoung小站
2020/05/05
1.9K0
简练的视图模型 ViewModel
patterns & practices Developer Center 发布了 Unity Application Block 1.2 for Silverlight - December 200
用户1172164
2018/01/16
9080
简练的视图模型 ViewModel
C++|对象模型|对象模型综述
作为C++的核心单元,对象模型在编译器眼中是如何实现的?本文从几个基本理论模型出发,剖析实际。
朝闻君
2021/11/22
6940
C++|对象模型|对象模型综述
创建局部模型视图
当模型中的表数量过多,导致关联变得复杂,不利于用户分析和理解表关系,而旧版Power BI中只提供这一种模型全局视图。
公众号PowerBI大师
2019/09/30
1K0
创建局部模型视图
【QT】QT模型/视图
MVC(Model-View-Controller)包括了3个组件:模型(model)是应用对象,用来表示数据;视图(View)是模型的用户界面,用来显示数据;控制(Controller)定义了用户界面对用户输入的反应方式。
半生瓜的blog
2023/05/13
3K0
【QT】QT模型/视图
Redis 的底层数据结构(对象)
目前为止,我们介绍了 redis 中非常典型的五种数据结构,从 SDS 到 压缩列表,这都是 redis 最底层、最常用的数据结构,相信你也掌握的不错。
Single
2019/12/02
4160
【C++】面向对象模型 ① ( 面向对象设计 | 面向对象底层实现机制 | 程序内存结构 )
C 语言中 , 数据 ( 变量 ) 和 行为 ( 函数 ) , 是 分开声明 的 , 数据 和 行为 之间 没有 关联性 , C 语言中不支持 数据 和 行为 的 封装 ;
韩曙亮
2023/10/15
2220
【C++】面向对象模型 ① ( 面向对象设计 | 面向对象底层实现机制 | 程序内存结构 )
辅助方法、模型、视图数据
在相应的视图中,使用 ViewBag 中的值来为 TextBox 辅助方法命名,可以实现渲染显示价格的文本框:
2018/09/03
6040
如何将PyTorch、TensorFlow模型转换为PaddlePaddle模型
将PyTorch模型转换为PaddlePaddle模型需要先把PyTorch转换为onnx模型,然后转换为PaddlePaddle模型。
用户1386409
2020/07/06
2.7K0
git对象模型
所有用来表示项目历史信息的文件,是通过一个40个字符的(40-digit)“对象名”来索引的,对象名看起来像这样:
用户3004328
2018/09/06
1.1K0
git对象模型
Java Class 对象模型的数据结构分析: ClassLoader 与 Modifier
Instances of the class Class represent classes and interfaces in a running Java application. An enum is a kind of class and an annotation is a kind of interface. Every array also belongs to a class that is reflected as a Class object that is shared by all arrays with the same element type and number of dimensions. The primitive Java types (boolean, byte, char, short, int, long, float, and double), and the keyword void are also represented as Class objects.
一个会写诗的程序员
2021/12/16
3570
OC对象模型
可以看出,alloc类方法是开辟了一块内存,生成了一个实例对象,并且对实例对象进行了初始化
Helloted
2022/06/06
6700
OC对象模型
Kubernetes对象模型
在之前的文章已经讲到了很多Kubernets对象,包括pod,service,deployment等等。Kubernets对象是一种持久化,表示集群状态的实体。它是一种声明式的意图的记录,一般使用yaml文件描述对象,它使用Kubernetes对象来表示集群的状态,通过API/kubectl管理Kubernetes对象。
方志朋
2019/05/26
9730
25.QT-模型视图
在Qt中,不管模型以什么结构组织数据,都必须为每个数据提供不同的索引值,使得视图能通过索引值访问模型中的具体数据
诺谦
2018/07/31
1.5K0
25.QT-模型视图
文档对象模型
DOM是针对HTML和XML文档的一个API(应用程序编程接口),DOM描绘了一个层次化的节点树,允许开发人员添加,移除,修改页面的某一部分。1998年10月DOM1级规范成为W3C的推荐标准,为基本的文档结构以及查询提供了接口。但是要注意,IE中的所有DOM对象都是以COM对象的形式实现的。这意味着IE中的DOM对象与原生JavaScript对象的行为或活动特点并不一致。
小小鱼儿小小林
2020/06/24
1.2K0
实验6 OpenGL模型视图变换
  (1)阅读教材有关三维图形变换原理,运行示范实验代码,掌握OPENGL程序三维图形变换的方法;   (2)阅读实验原理,运行示范实验代码,理解掌握OpenGL程序的模型视图变换。   (3)请分别调整观察变换矩阵、模型变换矩阵和投影变换矩阵的参数,观察变换结果;   (4)掌握三维观察流程、观察坐标系的确定、世界坐标系与观察坐标系之间的转换、平行投影和透视投影的特点,观察空间与规范化观察空间的概念。理解OpenGL图形库下视点函数、正交投影函数、透视投影函数。理解三维图形显示与观察代码实例。
步行者08
2020/10/27
2.1K0
实验6  OpenGL模型视图变换
如何将自己开发的模型转换为TensorFlow Lite可用模型
对于开发者来说,在移动设备上运行预先训练好的模型的能力意味着向边界计算(edge computing)迈进了一大步。[译注:所谓的边界计算,从字面意思理解,就是与现实世界的边界。数据中心是网络的中心,PC、手机、监控照相机处在边界。]数据能够直接在用户手机上处理,私人数据仍然掌握在他们手中。没有蜂窝网络的延迟,应用程序可以运行得更顺畅,并且可大幅减少公司的云服务账单。快速响应式应用现在可以运行复杂的机器学习模型,这种技术转变将赋予产品工程师跳出条条框框思考的力量,迎来应用程序开发的新潮流。
云水木石
2019/07/01
3.1K0
如何将自己开发的模型转换为TensorFlow Lite可用模型
Maven的项目对象模型
Maven包含了一个项目对象模型 (Project Object Model),一组标准集合,一个项目生命周期(Project Lifecycle),一个依赖管理系统(Dependency Management System),和用来运行定义在生命周期阶段(phase)中插件(plugin)目标(goal)的逻辑。
陈不成i
2021/06/29
6720
PHP对象的内存模型
数据段(data segment):是指用来存放程序中已初始化且不为0的全局变量如:静态变量和常量;
用户7657330
2020/08/14
1.9K0
CAS底层原理(cas理论模型)
CAS的全称为Compare-And-Swap ,它是一条CPU并发原语。它的功能是判断内存某个位置的值是否为预期值,如果是则更新为新的值,这个过程是原子的。
全栈程序员站长
2022/07/29
1.2K0
CAS底层原理(cas理论模型)

相似问题

如果模型不实现INotifyPropertyChanged,视图模型如何从其底层模型传播更改通知?

20

如何提取底层模型对象?

18

通知模型/模式

20

如何通知模型/视图底层数据更改了表标题?

11

如何引用django模型表单对象的底层模型?

21
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文