Qt QUndoStack、QUndoCommand(实现撤回和回撤)

  • 用到的类:

    1 QUndoStack: 一个存放 QUndoCommand 命令的栈.
    2 QUndoCommand:The QUndoCommand class is the base class of all commands stored on a QUndoStack.
    3 QUndoView:The QUndoView class displays the contents of a QUndoStack.(显示QUndoStack的内容)

    下面的例子是根据 Qt 自带的例子(undoframework)写的:

     

    重写 QGraphicsPolygonItem (方块)

    myitem.h

     1 #ifndef MYITEM_H
     2 #define MYITEM_H
     3 
     4 #include <QGraphicsItem>
     5 
     6 class myItem :public QGraphicsPolygonItem
     7 {
     8 
     9 public:
    10 
    11     enum {Type = UserType +1};
    12 
    13     explicit myItem(QGraphicsItem *parent = 0);
    14 
    15     int type() const override{return Type;}
    16 private:
    17     QPolygonF m_boxItem;
    18 };
    19 
    20 #endif // MYITEM_H

    myitem.cpp

     1 #include "myitem.h"
     2 #include <QBrush>
     3 myItem::myItem(QGraphicsItem *parent)
     4 {
     5 
     6     m_boxItem << QPointF(0,0) << QPointF(30,0)
     7               << QPointF(30,30) << QPointF(0,30)
     8               << QPointF(0,0);
     9     setPolygon(m_boxItem);
    10     //颜色随机
    11     QColor color( (qrand() % 256),(qrand() % 256),(qrand() % 256) );
    12 
    13     QBrush brush(color);
    14     setBrush(brush);
    15     //可移动
    16     setFlag(QGraphicsItem::ItemIsMovable);
    17     //可选中
    18     setFlag(QGraphicsItem::ItemIsSelectable);
    19 }

    重写 QGraphicsScene(场景)

    myscene.h

     1 #ifndef MYSCENE_H
     2 #define MYSCENE_H
     3 
     4 #include <QGraphicsScene>
     5 #include <QObject>
     6 #include "myitem.h"
     7 class myScene : public QGraphicsScene
     8 {
     9     Q_OBJECT
    10 public:
    11     myScene(QObject *parent = 0);
    12 signals:
    13 
    14     void itemMoveSignal(myItem* item,const QPointF position);
    15 
    16 protected:
    17     void mousePressEvent(QGraphicsSceneMouseEvent *event);
    18     void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
    19 
    20 private:
    21 
    22     QGraphicsItem * m_Item;
    23     QPointF m_oldPos;
    24 };
    25 
    26 #endif // MYSCENE_H

    myscene.cpp

     1 #include "myscene.h"
     2 #include <QGraphicsSceneMouseEvent>
     3 #include <QDebug>
     4 myScene::myScene(QObject *parent)
     5 {
     6     m_Item = 0;
     7 
     8 }
     9 
    10 void myScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
    11 {
    12     QPointF mousePos (event->buttonDownScenePos(Qt::LeftButton).x(),
    13                        event->buttonDownScenePos(Qt::LeftButton).y());
    14     const QList<QGraphicsItem* >itemList = items(mousePos);
    15 
    16     m_Item = itemList.isEmpty() ? 0 :itemList.first();
    17 
    18     if(m_Item != 0 && event->button() == Qt::LeftButton)
    19         m_oldPos = m_Item->pos();
    20 
    21     QGraphicsScene::mousePressEvent(event);
    22 
    23 }
    24 
    25 void myScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
    26 {
    27     if(m_Item != 0 && event->button() == Qt::LeftButton)
    28     {
    29         if(m_oldPos != m_Item->pos())
    30         //发送位置移动的信号
    31             emit itemMoveSignal(qgraphicsitem_cast<myItem*>(m_Item),m_oldPos);
    32     m_Item = 0;
    33     }
    34     QGraphicsScene::mouseReleaseEvent(event);
    35 }

    下面重写的 QUndoCommand 才是实现撤回和回撤的模块

    重写 QUndoCommand 就是重写父类的 undo() 和 redo() 方法

    mycommand.h

     1 #ifndef MYCOMMAND_H
     2 #define MYCOMMAND_H
     3 
     4 #include <QUndoCommand>
     5 #include "myitem.h"
     6 #include "myscene.h"
     7 //添加item
     8 class addCommand :public QUndoCommand
     9 {
    10 public :
    11     addCommand(QGraphicsScene* graphicsScene,QUndoCommand* parent = 0);
    12 
    13     void redo() override;//重写这两个函数
    14     void undo() override;
    15 private:
    16 
    17     myItem* m_item;
    18 
    19     QGraphicsScene* m_scene;
    20 
    21     QPointF m_initPos;
    22 };
    23 //移动item
    24 class moveCommand:public QUndoCommand
    25 {
    26 public:
    27     moveCommand(myItem* item,const QPointF oldPos,QUndoCommand* parent = 0);
    28 
    29     void redo() override;//重写这两个函数
    30     void undo() override;
    31 private:
    32     myItem* m_item;
    33     QPointF m_oldPos;
    34     QPointF m_newPos;
    35 
    36 };
    37 
    38 #endif // MYCOMMAND_H

    mycommand.cpp

     1 #include "mycommand.h"
     2 
     3 
     4 addCommand::addCommand(QGraphicsScene *graphicsScene, QUndoCommand *parent)
     5 {
     6     m_scene = graphicsScene;
     7 
     8     m_item = new myItem();
     9 
    10     m_initPos = QPointF(10,10); //初始化item 生成的位置
    11 
    12     setText("add item");//undoView 中就会显示(父类的方法)
    13 }
    14 
    15 void addCommand::redo()//stack push 时 会自动调用
    16 {
    17     m_scene->addItem(m_item);
    18     m_item->setPos(m_initPos);
    19     m_scene->clearSelection();
    20     m_scene->update();
    21 }
    22 
    23 void addCommand::undo()
    24 {
    25     m_scene->removeItem(m_item);
    26     m_scene->update();
    27 }
    28 
    29 moveCommand::moveCommand(myItem *item, const QPointF oldPos, QUndoCommand *parent)
    30 {
    31     m_item = item;
    32 
    33     m_newPos = m_item->pos();
    34 
    35     m_oldPos = oldPos;
    36 }
    37 
    38 void moveCommand::redo()
    39 {
    40     m_item->setPos(m_newPos);
    41     setText(QString("Move Item:(%1,%2)").arg(m_item->pos().rx()).arg(m_item->pos().ry()));
    42 }
    43 
    44 void moveCommand::undo()
    45 {
    46     m_item->setPos(m_oldPos);
    47     m_item->scene()->update();
    48     setText(QString("Move Item:(%1,%2)").arg(m_item->pos().rx()).arg(m_item->pos().ry()));
    49 }

    主界面

    widget.h

     1 #ifndef WIDGET_H
     2 #define WIDGET_H
     3 
     4 #include <QWidget>
     5 #include <QPushButton>
     6 #include <QGraphicsView>
     7 #include <QUndoStack>
     8 #include <QUndoView>
     9 
    10 #include "myscene.h"
    11 #include "myitem.h"
    12 #include "mycommand.h"
    13 namespace Ui {
    14 class Widget;
    15 }
    16 
    17 class Widget : public QWidget
    18 {
    19     Q_OBJECT
    20 
    21 public:
    22     explicit Widget(QWidget *parent = 0);
    23     ~Widget();
    24 
    25     void initUi();
    26 
    27     void initAction();
    28 
    29     void addItem();
    30 
    31     void itemMoved(myItem* item,QPointF pos);
    32 
    33 private:
    34     Ui::Widget *ui;
    35     QPushButton* m_addItemBtn;
    36     QAction* m_undoAction;
    37     QAction* m_redoAction;
    38     myScene *m_scene;
    39 
    40     QUndoStack* m_undoStack;
    41     QUndoView* m_undoView;
    42 };
    43 
    44 #endif // WIDGET_H

    widget.cpp

     1 #include "widget.h"
     2 #include "ui_widget.h"
     3 #include <QLayout>
     4 
     5 Widget::Widget(QWidget *parent) :
     6     QWidget(parent),
     7     ui(new Ui::Widget)
     8 {
     9     ui->setupUi(this);
    10 
    11 
    12     initAction();
    13 
    14     initUi();
    15 }
    16 
    17 Widget::~Widget()
    18 {
    19     delete ui;
    20 }
    21 
    22 void Widget::initUi()
    23 {
    24     this->setWindowTitle("码农小明--撤销回撤");
    25 
    26     m_addItemBtn = new QPushButton();
    27     m_addItemBtn->setText("add Item");
    28 
    29     connect(m_addItemBtn,&QPushButton::clicked,this,&Widget::addItem);
    30 
    31     m_scene = new myScene();
    32     QBrush brush(Qt::gray);
    33     m_scene->setSceneRect(QRect(0,0,200,300));
    34     m_scene->setBackgroundBrush(brush);
    35 
    36     connect(m_scene,&myScene::itemMoveSignal,this,&Widget::itemMoved);
    37 
    38 
    39     QGraphicsView *view = new QGraphicsView(m_scene);
    40 
    41     QVBoxLayout *pLayout = new QVBoxLayout();
    42     pLayout->addWidget(m_addItemBtn);
    43     pLayout->addWidget(view);
    44 
    45 
    46     m_undoView = new QUndoView(m_undoStack);//右面显示栈内容的view(不setText就是空的)
    47     QHBoxLayout *pHLayout = new QHBoxLayout();
    48     pHLayout->addLayout(pLayout);
    49     pHLayout->addWidget(m_undoView);
    50 
    51 
    52     this->setLayout(pHLayout);
    53 
    54     this->resize(500,400);
    55 
    56 }
    57 
    58 void Widget::initAction()
    59 {
    60     m_undoStack = new QUndoStack(this);//存放操作的栈
    61 
    62     m_undoAction = m_undoStack->createUndoAction(this,"Undo");
    63     m_undoAction->setShortcut(QKeySequence::Undo);
    64 
    65     m_redoAction = m_undoStack->createRedoAction(this,"Redo");
    66     m_redoAction->setShortcut(QKeySequence::Redo);
    67 
    68     this->addAction(m_undoAction);
    69     this->addAction(m_redoAction);
    70 }
    71 
    72 void Widget::addItem()
    73 {
    74     QUndoCommand* add = new addCommand(m_scene);
    75     m_undoStack->push(add);//入栈操作 会自动调用 addCommand 的 redo
    76 
    77 }
    78 
    79 void Widget::itemMoved(myItem *item, QPointF pos)
    80 {
    81     m_undoStack->push(new moveCommand(item,pos));//入栈操作
    82 }
### 回答1: Qt QUndoStack是一个用于管理撤销和重做操作的类。在Qt,QUndoStack是QUndoCommand类的栈,它允许用户执行操作并对这些操作进行撤销和重做。 QUndoStack提供了以下一些主要功能: 1. 操作的记录和执行:QUndoStack可以记录用户执行的操作,并将其添加到栈。当需要执行某个操作时,可以使用QUndoStack的redo()函数来执行最后一个撤销的操作。这对于实现撤销和重做功能非常有用。 2. 撤销和重做操作:QUndoStack可以根据需要撤销和重做操作。使用undo()函数可以撤销最后一个操作,而redo()函数可以重做最后一个被撤销的操作。 3. 操作的组合:QUndoStack还可以将多个操作组合成单个操作。这对于需要一次性撤销或重做多个操作的情况非常有用。 4. 操作的查询:QUndoStack还提供了查询栈操作状态的功能。可以通过isClean()函数来检查栈是否为空,可以使用canUndo()函数来判断是否有操作可以被撤销,可以使用canRedo()函数来判断是否有操作可以被重做。 总之,QUndoStack是一个在Qt用于管理撤销和重做操作的有用类。通过使用QUndoStack,我们可以轻松地实现撤销和重做功能,并为用户提供更好的交互体验。 ### 回答2: Qt QUndoStack 是一个用于管理撤销和重做操作的类。它是Qt框架的一部分,用于实现用户界面的撤销和重做功能。 QUndoStack 可以被视为一个命令历史记录,它保存了一系列的命令并跟踪它们的执行次序。当用户执行一个操作时,该操作会被包装成一个命令对象并被添加到 QUndoStack 。撤销操作时,命令对象会依次被调用撤销函数,从而达到撤销的效果。重做操作时,命令对象会依次被调用重做函数,从而实现重做的效果。 QUndoStack 还提供了一些管理命令历史记录的函数,如撤销、重做、清空等。它还支持嵌套撤销和重做操作,即在一个操作的撤销函数或重做函数可以执行其他的撤销和重做操作。 通过使用 QUndoStack开发者可以很方便地为用户提供撤销和重做功能,使用户对其操作更加灵活和便捷。QUndoStack 可以与其他 Qt 构件如 QAction、QUndoView 等配合使用,从而实现更强大的撤销和重做功能。 总的来说,Qt QUndoStack 是一个强大、易用的类,它为开发者提供了一种方便的方式来管理撤销和重做操作,使用户界面更加友好和可操作。 ### 回答3: Qt QUndoStackQt框架提供的用于管理撤销/重做操作的机制。它是一个用于处理用户操作历史记录的类,可以轻松地实现撤销和重做功能。 QUndoStack类提供了以下功能: 1. 可以将用户的操作(如添加、修改、删除等)存储在历史记录,以便将来可以对其进行撤销和重做。 2. 可以管理操作堆栈的大小,以避免无限增长的历史记录。 3. 可以跟踪操作的执行状态,例如是否可以撤销、重做、添加操作是否可用等。 4. 可以方便地在用户界面显示当前操作的信息,例如撤销和重做按钮的启用状态、当前操作的名称等。 5. 可以通过信号和槽机制与其他对象进行通信,以便在操作执行时进行相应的更新。 使用QUndoStack开发人员可以轻松地集成撤销和重做功能到他们的应用程序。只需将用户的操作添加到QUndoStack,该类会自动为你管理操作的历史记录,并确保所有状态的正确性。同时,QUndoStack还提供了便捷的方法来执行撤销和重做操作,以及查询操作的状态。 总而言之,Qt QUndoStack是一个非常有用的类,它提供了一个方便的机制来管理用户操作历史记录,并实现撤销和重做功能。无论是在桌面应用程序还是移动应用程序,QUndoStack都可以帮助开发人员提供更流畅和友好的用户体验。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蝈蝈(GuoGuo)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值