一、功能
通过给 QGraphicsScene 添加、删除、移动 QGraphicsPolygonItem 来演示 撤销重做功能
标签 undo framework example
二、核心代码,以添加图例为例
MainWindow.cpp 的核心代码
//1 创建堆栈
undoStack = new QUndoStack(this);
//2 以列表的形式显示堆栈信息(命令名称)
undoView = new QUndoView(undoStack);
undoView->setWindowTitle(tr("Command List"));
undoView->show();
undoView->setAttribute(Qt::WA_QuitOnClose, false);
//3 添加菜单动作:添加正方形图例
addBoxAction = new QAction(tr("Add &Box"), this);
addBoxAction->setShortcut(tr("Ctrl+O"));
connect(addBoxAction, SIGNAL(triggered()), this, SLOT(addBox()));
//4 添加菜单动作:撤销、重做
undoAction = undoStack->createUndoAction(this, tr("&Undo"));
undoAction->setShortcuts(QKeySequence::Undo);
redoAction = undoStack->createRedoAction(this, tr("&Redo"));
redoAction->setShortcuts(QKeySequence::Redo);
//5 添加正方形图例的动作
void MainWindow::addBox()
{
//创建添加命令
QUndoCommand *addCommand = new AddCommand(DiagramItem::Box, diagramScene);
//放入堆栈,,放入后 undoStack 会主动调用 addCommand 的 redo 动作
undoStack->push(addCommand);
}
添加命令的代码
class AddCommand : public QUndoCommand
{
public:
AddCommand(DiagramItem::DiagramType addType, QGraphicsScene *graphicsScene,
QUndoCommand *parent = 0);
~AddCommand();
void undo() override;
void redo() override;
private:
DiagramItem *myDiagramItem;
QGraphicsScene *myGraphicsScene;
QPointF initialPosition;
};
AddCommand::AddCommand(DiagramItem::DiagramType addType,
QGraphicsScene *scene, QUndoCommand *parent)
: QUndoCommand(parent)
{
static int itemCount = 0;
myGraphicsScene = scene; //保存场景,也就是接受者
myDiagramItem = new DiagramItem(addType);
initialPosition = QPointF((itemCount * 15) % int(scene->width()),
(itemCount * 15) % int(scene->height()));
scene->update();
++itemCount;
setText(QObject::tr("Add %1")
.arg(createCommandString(myDiagramItem, initialPosition)));
}
AddCommand::~AddCommand()
{
if (!myDiagramItem->scene())
delete myDiagramItem;
}
//撤销动作:从场景中删除当前item
void AddCommand::undo()
{
myGraphicsScene->removeItem(myDiagramItem);
myGraphicsScene->update();
}
//重做动作:将当前item 重新添加到场景
void AddCommand::redo()
{
myGraphicsScene->addItem(myDiagramItem);
myDiagramItem->setPos(initialPosition); //初始位置
myGraphicsScene->clearSelection();
myGraphicsScene->update();
}
三、撤销重做是 命令模式的一种体现
命令(Command):定义命令的接口,通常包含执行和撤销两个方法。具体命令(ConcreteCommand):实现命令接口,包含了对应的操作。命令接收者(Receiver):执行命令的对象。命令发起者(Invoker):调用命令的对象,负责将命令发送给命令接收者。客户端(Client):创建命令对象并将其发送给命令发起者。
对于该范例
命令(Command):QUndoCommand是命令接口。它定义了执行(redo)和撤销(undo)的方法。具体命令(ConcreteCommand):AddCommand是具体的命令。它是 QUndoCommand的子类,实现了 redo和undo方法。命令接收者(Receiver):QGraphicsScene是命令的接收者。它是执行命令的对象,AddCommand的 redo和 undo方法都是操作 QGraphicsScene。命令发起者(Invoker):QUndoStack是命令的发起者。它负责调用和存储命令。菜单栏的动作addBoxAction实际上也扮演了命令发起者的角色,因为它们是触发执行或撤销命令的实际用户界面元素。客户端(Client):在这个例子中,MainWindow就是客户端。它创建了应用程序,包括命令接收者(QGraphicsScene)、命令发起者(QUndoStack 和 菜单栏)、并在 菜单动作执行时创建 AddCommand 命令。
精彩文章
发表评论