Qt QUndoStack、QUndoCommand(实现撤回和回撤)
创始人
2024-02-09 16:58:00
  • 用到的类:

    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_H2 #define MYITEM_H3 4 #include 5 6 class myItem :public QGraphicsPolygonItem7 {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 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_H2 #define MYSCENE_H3 4 #include 5 #include 6 #include "myitem.h"7 class myScene : public QGraphicsScene8 {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 3 #include 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 QListitemList = 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(m_Item),m_oldPos);
    32     m_Item = 0;
    33     }
    34     QGraphicsScene::mouseReleaseEvent(event);
    35 }

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

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

    mycommand.h

     1 #ifndef MYCOMMAND_H2 #define MYCOMMAND_H3 4 #include 5 #include "myitem.h"6 #include "myscene.h"7 //添加item8 class addCommand :public QUndoCommand9 {
    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_H2 #define WIDGET_H3 4 #include 5 #include 6 #include 7 #include 8 #include 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 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 }

相关内容

热门资讯

苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...