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 }
  • 相关阅读:
    tree命令详解
    rm 命令详解
    rename命令详解
    pwd命令详解
    mv命令详解
    mkdir命令详情
    find命令详解
    dockerfile中配置时区
    docker导入导出
    docker上传私有仓库报错
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/12836278.html
Copyright © 2011-2022 走看看