Overview of Qt's Undo Framework

Introduction

Qt's Undo Framework is an implementation of the Command pattern, for implementing undo/redo functionality in applications.

The Command pattern is based on the idea that all editing in an application is done by creating instances of command objects. Command objects apply changes to the document and are stored on a command stack. Furthermore(此外), each command knows how to undo its changes to bring the document back to its previous state. As long as the application only uses command objects to change the state of the document, it is possible to undo a sequence of commands by traversing the stack downwards and calling undo on each command in turn. It is also possible to redo a sequence of commands by traversing the stack upwards and calling redo on each command.

Classes

The framework consists of four classes:

  1. QUndoCommand is the base class of all commands stored on an undo stack. It can apply (redo) or undo a single change in the document.
  2. QUndoStack is a list of QUndoCommand objects. It contains all the commands executed on the document and can roll the document's state backwards or forwards by undoing or redoing them.
  3. QUndoGroup is a group of undo stacks. It is useful when an application contains more than one undo stack, typically one for each opened document. QUndoGroup provides a single pair of undo/redo slots for all the stacks in the group. It forwards undo and redo requests to the active stack, which is the stack associated with the document that is currently being edited by the user.
  4. QUndoView is a widget which shows the contents of an undo stack. Clicking on a command in the view rolls the document's state backwards or forwards to that command.

Concepts

The following concepts are supported by the framework:

  • Clean state: Used to signal when the document enters and leaves a state that has been saved to disk. This is typically used to disable or enable the save actions, and to update the document's title bar.
  • Command compression: Used to compress sequences of commands into a single command. For example: In a text editor, the commands that insert individual characters into the document can be compressed into a single command that inserts whole sections of text. These bigger changes are more convenient for the user to undo and redo.
  • Command macros: A sequence of commands, all of which are undone or redone in one step. These simplify the task of writing an application, since a set of simpler commands can be composed into more complex commands. For example, a command that moves a set of selected objects in a document can be created by combining a set of commands, each of which moves a single object.

QUndoStack provides convenient undo and redo QAction objects that can be inserted into a menu or a toolbar. The text properties of these actions always reflect what command will be undone or redone when they are triggered. Similarly, QUndoGroup provides undo and redo actions that always behave like the undo and redo actions of the active stack.

QUndoCommand

The QUndoCommand class is the base class of all commands stored on a QUndoStack.

A QUndoCommand represents a single editing action on a document; for example, inserting or deleting a block of text in a text editor. QUndoCommand can apply a change to the document with redo() and undo the change with undo(). The implementations for these functions must be provided in a derived class.

class AppendText : public QUndoCommand
{
public:
AppendText(QString *doc, const QString &text)
: m_document(doc), m_text(text) { setText("append text"); }
virtual void undo()
{ m_document->chop(m_text.length()); }
virtual void redo()
{ m_document->append(m_text); }
private:
QString *m_document;
QString m_text;
};

A QUndoCommand has an associated text(). This is a short string describing what the command does. It is used to update the text properties of the stack's undo and redo actions; see QUndoStack::createUndoAction() and QUndoStack::createRedoAction().

QUndoCommand objects are owned by the stack they were pushed on. QUndoStack deletes a command if it has been undone and a new command is pushed. For example:

MyCommand *command1 = new MyCommand();
stack->push(command1);
MyCommand *command2 = new MyCommand();
stack->push(command2); stack->undo(); MyCommand *command3 = new MyCommand();
stack->push(command3); // command2 gets deleted

In effect, when a command is pushed, it becomes the top-most command on the stack.

To support command compression, QUndoCommand has an id() and the virtual function mergeWith(). These functions are used by QUndoStack::push().

To support command macros, a QUndoCommand object can have any number of child commands. Undoing or redoing the parent command will cause the child commands to be undone or redone. A command can be assigned to a parent explicitly in the constructor. In this case, the command will be owned by the parent.

The parent in this case is usually an empty command, in that it doesn't provide its own implementation of undo() and redo(). Instead, it uses the base implementations of these functions, which simply call undo() or redo() on all its children. The parent should, however, have a meaningful text().

QUndoCommand *insertRed = new QUndoCommand(); // an empty command
insertRed->setText("insert red text"); new InsertText(document, idx, text, insertRed); // becomes child of insertRed
new SetColor(document, idx, text.length(), Qt::red, insertRed); stack.push(insertRed);

Another way to create macros is to use the convenience functions QUndoStack::beginMacro() and QUndoStack::endMacro().

QUndoStack

The QUndoStack class is a stack of QUndoCommand objects.

An undo stack maintains a stack of commands that have been applied to a document.

New commands are pushed on the stack using push(). Commands can be undone and redone using undo() and redo(), or by triggering the actions returned by createUndoAction() and createRedoAction().

QUndoStack keeps track of the current command. This is the command which will be executed by the next call to redo(). The index of this command is returned by index(). The state of the edited object can be rolled forward or back using setIndex(). If the top-most command on the stack has already been redone, index() is equal to count().

QUndoStack provides support for undo and redo actions, command compression, command macros, and supports the concept of a clean state.

Undo and Redo Actions

QUndoStack provides convenient undo and redo QAction objects, which can be inserted into a menu or a toolbar. When commands are undone or redone, QUndoStack updates the text properties of these actions to reflect what change they will trigger. The actions are also disabled when no command is available for undo or redo. These actions are returned by QUndoStack::createUndoAction() and QUndoStack::createRedoAction().

Clean State

QUndoStack supports the concept of a clean state. When the document is saved to disk, the stack can be marked as clean using setClean(). Whenever the stack returns to this state through undoing and redoing commands, it emits the signal cleanChanged(). This signal is also emitted when the stack leaves the clean state. This signal is usually used to enable and disable the save actions in the application, and to update the document's title to reflect that it contains unsaved changes.

Obsolete Commands

QUndoStack is able to delete commands from the stack if the command is no longer needed. One example may be to delete a command when two commands are merged together in such a way that the merged command has no function. This can be seen with move commands where the user moves their mouse to one part of the screen and then moves it to the original position. The merged command results in a mouse movement of 0. This command can be deleted since it serves no purpose. Another example is with networking commands that fail due to connection issues. In this case, the command is to be removed from the stack because the redo() and undo() functions have no function since there was connection issues.

A command can be marked obsolete(过时的) with the QUndoCommand::setObsolete() function. The QUndoCommand::isObsolete() flag is checked in QUndoStack::push(), QUndoStack::undo(), QUndoStack::redo(), and QUndoStack::setIndex() after calling QUndoCommand::undo(), QUndoCommand::redo() and QUndoCommand:mergeWith() where applicable.

If a command is set obsolete and the clean index is greater than or equal to the current command index, then the clean index will be reset when the command is deleted from the stack.

QUndoGroup

The QUndoGroup class is a group of QUndoStack objects.

An application often has multiple undo stacks, one for each opened document. At the same time, an application usually has one undo action and one redo action, which triggers undo or redo in the active document.

QUndoGroup is a group of QUndoStack objects, one of which may be active. It has an undo() and redo() slot, which calls QUndoStack::undo() and QUndoStack::redo() for the active stack. It also has the functions createUndoAction() and createRedoAction(). The actions returned by these functions behave in the same way as those returned by QUndoStack::createUndoAction() and QUndoStack::createRedoAction() of the active stack.

Stacks are added to a group with addStack() and removed with removeStack(). A stack is implicitly added to a group when it is created with the group as its parent QObject.

It is the programmer's responsibility to specify which stack is active by calling QUndoStack::setActive(), usually when the associated document window receives focus. The active stack may also be set with setActiveStack(), and is returned by activeStack().

When a stack is added to a group using addStack(), the group does not take ownership of the stack. This means the stack has to be deleted separately from the group. When a stack is deleted, it is automatically removed from a group. A stack may belong to only one group. Adding it to another group will cause it to be removed from the previous group.

A QUndoGroup is also useful in conjunction with QUndoView. If a QUndoView is set to watch a group using QUndoView::setGroup(), it will update itself to display the active stack.

QUndoView`

The QUndoView class displays the contents of a QUndoStack.

QUndoView is a QListView which displays the list of commands pushed on an undo stack. The most recently executed command is always selected. Selecting a different command results in a call to QUndoStack::setIndex(), rolling the state of the document backwards or forward to the new command.

The stack can be set explicitly with setStack(). Alternatively, a QUndoGroup object can be set with setGroup(). The view will then update itself automatically whenever the active stack of the group changes.

Demos

  1. undoframework
  2. undo

Reference

Qt Help manual


Qt's Undo Framework的更多相关文章

  1. Qt Undo Framework Demo

    Qt Undo Framework Demo eryar@163.com Abstract. Qt’s Undo Framework is an implementation of the Comma ...

  2. Qt Undo Framework

    Qt undo/redo 框架 基于Command设计模式 支持命令压缩和命令合成 提供了与工具包其他部分融合很好的widgets和actions 术语(Terminology) Command - ...

  3. qt Graphics View Framework(非重点)

    Graphics View 提供了一种接口,用于管理大量自定义的 2D 图形元素,并与之进行交互:还提供了用于将这些元素进行可视化显示的观察组件,并支持缩放和旋转. 说明;Graphics View ...

  4. 很多人以为 connect 和 disconnect 应该像 new 和 delete 一样成对出现 这是错误的(只要 sender 或 receiver 其中之一不存在了,connect 会自动失效。QObject::connect 函数是线程安全的)

    其实我写文章也是边查资料边编辑的 有时候是怕自己的阐述不严谨,有时候是怕自己重复造轮子 就像有些人不停的教大家QLabel QDialog QWidget 个人是不屑的 命令模式 用 Qt's Und ...

  5. Undo/Redo for Qt Tree Model

    Undo/Redo for Qt Tree Model eryar@163.com Abstract. Qt contains a set of item view classes that use ...

  6. Qt: The State Machine Framework 学习

    State Machine,即为状态机,是Qt中一项非常好的框架.State Machine包括State以及State间的Transition,构成状态和状态转移.通过状态机,我们可以很方便地实现很 ...

  7. Qt的Model/View Framework解析(数据是从真正的“肉(raw)”里取得,Model提供肉,所以读写文件、操作数据库、网络通讯等一系列与数据打交道的工作就在model中做了)

    最近在看Qt的Model/View Framework,在网上搜了搜,好像中文的除了几篇翻译没有什么有价值的文章.E文的除了Qt的官方介绍,其它文章也很少.看到一个老外在blog中写道Model/Vi ...

  8. qt QUndoGroup的使用

    最近项目中用到撤销,恢复功能.qt的demo中有一个例子,是类似于单文档的.而我的项目中是类似于多文档的项目,即可能要打开多个页面,不同的页面都有撤销恢复功能.这样的话,就要用到QUndoGroup类 ...

  9. Qt Examples Qt实例汇总

    ActiveQt Examples Using ActiveX from Qt applications. Animation Framework Examples Doing animations ...

随机推荐

  1. 简单CSS3代码实现立方体以及3D骰子

    1 实现3D立方体 首先准备好UL以及6个Li: 代码如下 ul { position: absolute; top: 50%; left: 50%; transform:translate(-50% ...

  2. 前端 —— SVG

    0. 简介 SVG:可缩放矢量图形: SVG 是代码,通过浏览器的解析而渲染成一种图形: 可缩放矢量图形是基于可扩展标记语言(XML),以描述二维矢量图形的一种图形格式,由万维网联盟( World W ...

  3. python 编程中的一个关于图片的库 imageio (读取照片RGB内容,转换照片格式)

    最近在看机器学习方面的东西,经常遇到需要把某个类型的照片中 RGB 内容读取出来, 在python中照片显示用matplotlib就可以做到,但是导入不同格式的照片,保持出不同格式的照片numpy, ...

  4. np.ones(N)/N的作用

    在python中导入numpy包 N=5 weights = np.ones(N)/N       //这里就相当于创建了一个数组,且为5个1/5的数组 print "weights&quo ...

  5. 20155234 2016-2017-2 《Java程序设计》第8周学习总结

    20155234 2016-2017-2 <Java程序设计>第8周学习总结 教材学习内容总结 java.util.loggging包提供了日志功能相关类与接口. 使用日志的起点是Logg ...

  6. 优先队列底层实现是堆(heap)(操作系统进程调度)

    只有一个CPU的情况下,比如作业系统中的调度程序,当一个作业完成后,需要在所有等待调度的作业中选择一个优先级最高的作业来执行(删除),并且也可以添加一个新的作业到作业的优先队列中(插入). 插入操作 ...

  7. oracle10g精简版安装步骤

     Feng218 假设出现例如以下错误: 最好把360安全卫士全关了.再安装下.就没事了 然后安装完了进入时输入username:sys或者system password就是自己设好的passwo ...

  8. 零基础学Cocos2d-X 3.0 - 04

    忙完两个项目后.最终有时间继续学习Cocos2d-X 了. 常听人说.Cocos2d-X 有四个类是最经常使用的,包含: Director 类----> 导演 Scene 类 -----> ...

  9. Centos7配置 SNMP服务

    本文转载至:http://blog.51cto.com/5001660/2097212   一.安装yum源安装SNMP软件包 1.更新yum源: yum clean all yum makecach ...

  10. bzoj2660最多的方案

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2660 当然可以看出  选了第 i 个斐波那契数<=>选了第 i - 1 和第 i ...