一、功能        

        通过给 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 命令。

精彩文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: