zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    关于lockkeyword
    关于多层for循环迭代的效率优化问题
    Android 面试精华题目总结
    Linux基础回想(1)——Linux系统概述
    linux源代码编译安装OpenCV
    校赛热身 Problem C. Sometimes Naive (状压dp)
    校赛热身 Problem C. Sometimes Naive (状压dp)
    校赛热身 Problem B. Matrix Fast Power
    校赛热身 Problem B. Matrix Fast Power
    集合的划分(递推)
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/12836278.html
Copyright © 2011-2022 走看看