在应用程序开发中,撤销/重做功能已很常见。它允许用户在操作过程中随时撤销错误或不满意的变化,或者在撤销之后重新执行之前的操作。Qt 框架为此提供了一个强大的工具——QUndoStack,它简化了撤销/重做系统的实现,使得开发者能够高效、优雅地将这一功能集成到自己的应用程序中。本文将详细介绍 QUndoStack 的使用,辅以详细的 C++ 示例代码,帮助您快速掌握其实现原理与实践方法。
一、QUndoStack 的核心概念
1. QUndoCommand
QUndoStack 管理的对象是 QUndoCommand 类及其子类。QUndoCommand 是撤销/重做功能的基本单元,代表一个可逆操作。每个命令都需要重写以下两个虚函数:
void redo()
: 执行命令,应用修改。当用户请求重做时,QUndoStack 将调用此函数。void undo()
: 撤销命令,恢复到修改前的状态。当用户请求撤销时,QUndoStack 会调用此函数。
**示例:**创建一个插入QPushButton的 QUndoCommand 子类:
#include <QPushButton>
#include <QUndoCommand>
#include <QVBoxLayout>
class AddButtonCommand : public QUndoCommand
{
public:
AddButtonCommand(QVBoxLayout *vBoxLayout, QPushButton *pushButton);
void undo() override;
void redo() override;
private:
QPushButton *m_pushButton;
QVBoxLayout *m_vBoxLayout;
};
2. QUndoStack
QUndoStack 是一个 QUndoCommand 对象的堆栈,负责管理和执行撤销/重做操作。主要接口包括:
push(QUndoCommand*)
: 将命令压入堆栈,使其成为当前命令。undo()
: 执行堆栈顶部命令的undo()
函数。redo()
: 执行刚刚被撤销的命令的redo()
函数。createUndoAction(QObject*, const QString&)
: 创建关联到撤销功能的 QAction。createRedoAction(QObject*, const QString&)
: 创建关联到重做功能的 QAction。canUndo()
: 判断是否有可撤销的命令。canRedo()
: 判断是否有可重做的命令。clear()
: 清空堆栈。
二、QUndoStack 的实际应用
1. 初始化与命令推入
首先,创建 QUndoStack 实例:
QUndoStack* undoStack = new QUndoStack;
每当用户执行一个可撤销的操作时,创建相应的 QUndoCommand 子类实例,并将其推入 QUndoStack:
AddButtonCommand *cmd = new AddButtonCommand(ui->verticalLayout, pushButton);
this->m_undoStack->push(cmd);
2. 连接界面元素
将撤销和重做按钮的点击事件与 QUndoStack 的相应槽函数连接:
QAction *undoAction = new QAction("撤销");
connect(undoAction, &QAction::triggered, this->m_undoStack, &QUndoStack::undo);
QAction *redoAction = new QAction("重做");
connect(redoAction, &QAction::triggered, this->m_undoStack, &QUndoStack::redo);
3. 动态状态同步
利用 QUndoStack 发出的信号,保持界面与堆栈状态的同步:
connect(this->m_undoStack, &QUndoStack::canUndoChanged, [=]() {
undoAction->setEnabled(this->m_undoStack->canUndo());
});
connect(this->m_undoStack, &QUndoStack::canRedoChanged, [=]() {
redoAction->setEnabled(this->m_undoStack->canRedo());
});
根据 canUndo()
和 canRedo()
的返回值,更新对应按钮的启用状态和文本。
4. 分组命令
对于一系列相关操作,可以使用 beginMacro()
和 endMacro()
方法将它们分组为一个宏命令:
undoStack->beginMacro("Edit Text");
// Perform several related operations, each pushing their own command onto the stack
undoStack->endMacro();
用户在撤销时会一次性撤销整个宏,而非单个命令。
5. 清理堆栈
在适当时候(如保存文件或关闭文档后)清空堆栈:
undoStack->clear();
效果展示
三、结论
完整工程代码示例
QUndoStack 是 Qt 中实现撤销/重做功能的强大工具,它通过管理 QUndoCommand 对象的堆栈,极大地简化了这一复杂特性的实现过程。开发者只需创建命令子类,将命令推入堆栈,并将堆栈与用户界面交互(如按钮、菜单项)关联起来,即可轻松实现灵活且易于维护的撤销/重做机制。借助 QUndoStack,您的应用程序将拥有更高级别的用户友好性和交互体验。