Undo/Redo for Qt Tree Model
Undo/Redo for Qt Tree Model
Abstract. Qt contains a set of item view classes that use a model/view architecture to manage the relationship between data and the way it is presented to the user. The separation of functionality introduced by this architecture gives developers greater flexibility to customize the presentation of items, and provides a standard model interface to allow a wide range of data sources to be used with existing item views. Model 3D aided design software such as AVEVA Plant/PDMS, Marine use the architecture to manage the design data source. The article demonstrate the Undo/Redo on the Qt Tree model.
Key Words. Model/View, MVC pattern, Undo/Redo, Tree Model
1. Introduction
现 代稍微大型一点的软件,要处理的数据量通常会比较大。这时就需要有一个唯一的数据源,且会对这个数据源中的数据进行增、删、改的操作。如果没有统一的数据 源,数据会随意地被创建和删除,且创建和删除的用户界面也不统一,不利于软件管理。基于唯一的数据源,并在这个基础上提供统一的增删改接口,不仅有利于软 件数据管理,还有利于事务的处理,即Undo/Redo功能。若引入脚本语言,如Tcl或Python,甚至可实现脚本命令对数据的操作,为程序增加二次 开发功能。
![]()
Figure 1. AVEVA Plant/PDMS Software
如 上图1所示为英国剑桥大学CADCENTRE出品的AVEVA Plant/PDMS软件。PDMS使用了统一的数据源,左边的导航树及右边的三维模型都是这个数据源的一种展示方式,可以在导航树上创建及删除数据;也 可以在三维视图中进行交互,方便地创建及修改模型。这种方式与GoF描述的Observer观察者模式相似,即:
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
对应上面的软件,即对于唯一的数据源这个对象,导航树及三维视图都依赖于他。当数据源这个对象中有数据的增删改时,导航树及三维视图都会得到通知并自动更新了。
图1右下角的CommandWindow中可以输入命令,即PML,也可以对数据源进行修改。引入Observer模式,即可实现这些功能。
Qt 中包含了一系列的Model/View类,这些类都是基于MVC架构的,这种将数据与视图分开的处理,使同一个数据源可以不同的视图中进行展示,且不需要 修改数据源的结构。Qt中基于Command命令模式实现了一个Undo/Redo的框架,将Undo/Redo框架应用于Model/View的类,即 可得到与AVEVA Plant/PDMS中类似的功能。
本文主要对Qt中的model/view及undo/redo框架进行介绍,及如何将Undo/Redo框架应用到model/view中去,实现对以层次方式组织数据的树模型进行undo/redo,进而实现一个三维CAD工厂设计的原型。
2.Tree Model
软件中使用层次方式来组织数据,可护展性好。如OpenCASCADE中的OCAF框架的数据也是树形方式组织:
![]()
Figure 2.1 OpenCASCADE OCAF data tree
每 个Label中可以存放属性,还包含子Label,这样就提供了一个通用的程序框架,灵活使用,可以用一种统一的方式来存放数据。有一个缺点就是每个 Label中的属性类型只能包含一种,这种方式相对于AVEVA的自定义属性UDA来说,就显得很不方便了,需要提前对数据的存储进行规划,扩展起来稍有 不便。
AVEVA中对每个数据Element都提供了自定义属性(User Definable Attribute),每种类型的属性(数值型、字符串型等)都可以包含任意数量,没有限制。所以可扩展性更好。
Qt 中基于MVC模式的model/view架构提供了一些预定义的模型及视图,如列表模型及对应的视图,树模型及树视图等。在model/view架构中, 为model提供了统一的访问数据的方式,即Model Index。对于列表model,通过QModelIndex::row()即可访问。对于表格model,需要QModelIndex::row()和 QModelIndex::column()。对于树model,除了上述两个函数,还需要提供QModelIndex::parent()来对父节点进 行访问。如下图2.2所示:
![]()
Figure 2.2 Schematic view of Qt’s Models
若需要对列表及表格model应用Undo框架,还是很方便的,只要记住数据操作的对应的row或row及column即可。若要对树形model进行undo,原理也是一样的,即在redo中生成数据在undo中恢复数据。
3.Key Points
将undo框架与model/view结合有两种方式:
v 通过在undo/redo命令中调用QAbstractItemModel的API来改变底层数据;
v 自定义model使其创建命令并推送到undo栈Stack中去;
第 一种方式看起来要容易些,且可与任意model结合。The first approach seems simpler, as it works with any model and gives the undo framework total control --- you can create as many different types of commands as you want and each of them can call a number of methods from the model API in their undo() and redo() routines.
当model中有delete操作时,会将index内部的数据删除。对于这种情况,需要注意。Qt给出了两个解决办法:
There are two things to remember. The first is that, if you delete items, rows or columns, you should save the data of all the items getting deleted(including children) somewhere so that you can later revert the deletion. The second is that it would be nice to be able to set meaningful descriptions of commands pushed on the stack. To do that you can provide methods in the model, that are called each time a command is pushed onto the stack, which should each return a description based on the parameters of the command being executed.
基于上述思想,实现了Tree Model与Undo Framework结合的一个小例子:
![]()
Figure 3. Undo/Redo and Tree Model
4.Conclusion
Qt中基于Command命令模式的Undo框架,需要对数据操作及恢复仔细考量。尤其对于有删除数据的操作,若以QModelIndex作为参考依据,则会出错。对于此Qt提供了两个解决思路。
基于Qt的model/view及undo框架,也可以方便实现OpenCASCADE中的OCAF框架许多类似的功能,且Qt的代码可读性更高。若要快速开发程序,可以考虑使用Qt的model/view框架。
感谢晓天的建议。
5. References
1. Using Undo/Redo with Item Views. http://doc.qt.digia.com/qq/qq25-undo.html
2. OpenCASCADE. OCAF User’s Guide. 2014
3. GoF. Design Patterns-Element of Reusable Object-Oriented Software. 1995
PDF Version: Undo/Redo for Qt Tree Model
Undo/Redo for Qt Tree Model的更多相关文章
- Qt自定义model
前面我们说了Qt提供的几个预定义model.但是,面对变化万千的需求,那几个model是远远不能满足我们的需要的.另外,对于Qt这种框架来说,model的选择首先要能满足绝大多数功能的需要,这就是说, ...
- Qt的Model/View Framework解析(数据是从真正的“肉(raw)”里取得,Model提供肉,所以读写文件、操作数据库、网络通讯等一系列与数据打交道的工作就在model中做了)
最近在看Qt的Model/View Framework,在网上搜了搜,好像中文的除了几篇翻译没有什么有价值的文章.E文的除了Qt的官方介绍,其它文章也很少.看到一个老外在blog中写道Model/Vi ...
- MySQL,MariaDB:Undo | Redo [转]
本文是介绍MySQL数据库InnoDB存储引擎重做日志漫游 00 – Undo LogUndo Log 是为了实现事务的原子性,在MySQL数据库InnoDB存储引擎中,还用Undo Log来实现多版 ...
- iOS: 为画板App增加 Undo/Redo(撤销/重做)操作
这个随笔的内容以上一个随笔为基础,(在iOS中实现一个简单的画板),上一个随笔实现了一个简单的画板: 今天我们要为这个画板增加Undo/Redo操作,当画错了一笔,可以撤销它,或者撤销之后后悔了, ...
- [转]MySQL日志——Undo | Redo
本文是介绍MySQL数据库InnoDB存储引擎重做日志漫游 00 – Undo LogUndo Log 是为了实现事务的原子性,在MySQL数据库InnoDB存储引擎中,还用Undo Log来实现多版 ...
- 从Undo,Redo谈命令模式
一般的应用软件中,通常会提供Redo和Undo的操作,比如Paint.NET中的动作面板,Word中的撤销重做,一般我们按Ctrl-Z即可回退到上次操作. 要实现上面的这一功能,最直观的想法就是,我们 ...
- 【转载】MySQL 日志 undo | redo
本文是介绍MySQL数据库InnoDB存储引擎重做日志漫游 00 – Undo LogUndo Log 是为了实现事务的原子性,在MySQL数据库InnoDB存储引擎中,还用Undo Log来实现多版 ...
- MySQL InnoDB存储引擎undo redo解析
本文介绍MySQL数据库InnoDB存储引擎重做日志漫游 00 – Undo Log Undo Log 为了实现事务原子,在MySQL数据库InnoDB存储引擎,还使用Undo Log(简称:MVCC ...
- MySQL日志Undo&Redo
00 – Undo LogUndo Log 是为了实现事务的原子性,在MySQL数据库InnoDB存储引擎中,还用Undo Log来实现多版本并发控制(简称:MVCC). - 事务的原子性(Atomi ...
随机推荐
- hello!
今天是个星期天 第一次开通了朕的博客 么么哒 感觉很困 唔~晚安zzzzz
- 20161023 NOIP 模拟赛 T2 解题报告
Task 2.回文串计数 (calc.pas/calc.c/calc.cpp) [题目描述] 虽然是一名理科生,Mcx常常声称自己是一名真正的文科生.不知为何,他对于背诵总有一种莫名的热爱,这也促使他 ...
- bzoj1026数位dp
基础的数位dp 但是ce了一发,(abs难道不是cmath里的吗?改成bits/stdc++.h就过了) #include <bits/stdc++.h> using namespace ...
- bzoj1927最小费用最大流
其实本来打算做最小费用最大流的题目前先来点模板题的,,,结果看到这道题二话不说(之前打太多了)敲了一个dinic,快写完了发现不对 我当时就这表情→ =_=你TM逗我 刚要删突然感觉dinic的模 ...
- 【JBOSS】控制台数据库连接信息
数据库连接 信息 进入 在这个页面中(IP和端口已自己的为主):ConnectionCount 这个项目代表在服务开启后,总共使用的连接数!ConnectionCreatedCount ...
- Linux上的free命令详解、swap机制
Linux上的free命令详解 解释一下Linux上free命令的输出. 下面是free的运行结果,一共有4行.为了方便说明,我加上了列号.这样可以把free的输出看成一个二维数组FO(Free ...
- Editbox之三个框框
自重装系统后,电脑中两个版本的eclipse都驾崩了,起个VS也要花费半年的时间(观赏收费),所以就运用已有的工具STS编了代码,不能用JavaFX很是遗憾,只能在网上找了代码,自己修改后完成了测试. ...
- ajax内调用WCF服务
WCF可以当作WebService一样被调用,在html内通过ajax调用WCF服务的方法如下: 1.新建一个WCF服务的网站项目: 2.在项目内增加一个新项:启用了ajax的WCF服务: 3.在对应 ...
- TPC-H生成.tbl文件导入postgresql数据库的坑
数据库project好好的不用主流的MySQL和Microsoft server而要求用听都没听过的postgresql (当然,可能你三个都没听过) 这里的坑主要是把生成的那八张.tbl的表导入pg ...
- HTML5新标签<canvas>
基本用法 首先在body中写个<canvas>,设定大小,个人建议大小要在行内设置,不然在部分情况下会发生错误. CSS部分 给canvas加个边框,这边框只是为了方便看出canvas的边 ...