QT 范例阅读: undoframework

一、功能        

        通过给 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();
}

三、撤销重做是 命令模式的一种体现 

  1. 命令(Command):定义命令的接口,通常包含执行和撤销两个方法。
  2. 具体命令(ConcreteCommand):实现命令接口,包含了对应的操作。
  3. 命令接收者(Receiver):执行命令的对象。
  4. 命令发起者(Invoker):调用命令的对象,负责将命令发送给命令接收者。
  5. 客户端(Client):创建命令对象并将其发送给命令发起者。

        对于该范例

  1. 命令(Command)QUndoCommand是命令接口。它定义了执行(redo)和撤销(undo)的方法。
  2. 具体命令(ConcreteCommand)AddCommand是具体的命令。它是 QUndoCommand的子类,实现了 redoundo方法。
  3. 命令接收者(Receiver)QGraphicsScene是命令的接收者。它是执行命令的对象,AddCommand的 redo和 undo方法都是操作 QGraphicsScene
  4. 命令发起者(Invoker)QUndoStack是命令的发起者。它负责调用和存储命令。菜单栏的动作addBoxAction实际上也扮演了命令发起者的角色,因为它们是触发执行或撤销命令的实际用户界面元素。
  5. 客户端(Client):在这个例子中,MainWindow就是客户端。它创建了应用程序,包括命令接收者(QGraphicsScene)、命令发起者(QUndoStack 和 菜单栏)、并在 菜单动作执行时创建 AddCommand 命令

你可能感兴趣的:(QT,qt)