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 }

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM