用到的类:
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 (方块)
【领QT开发教程学习资料,点击下方链接免费领取↓↓,先码住不迷路~】
点击→领取「链接」
myitem.h
#ifndef MYITEM_H
#define MYITEM_H
#include <QGraphicsItem>
class myItem :public QGraphicsPolygonItem
{
public:
enum {Type = UserType +1};
explicit myItem(QGraphicsItem *parent = 0);
int type() const override{return Type;}
private:
QPolygonF m_boxItem;
};
#endif // MYITEM_H
myitem.cpp
#include "myitem.h"
#include <QBrush>
myItem::myItem(QGraphicsItem *parent)
{
m_boxItem << QPointF(0,0) << QPointF(30,0)
<< QPointF(30,30) << QPointF(0,30)
<< QPointF(0,0);
setPolygon(m_boxItem);
//颜色随机
QColor color( (qrand() % 256),(qrand() % 256),(qrand() % 256) );
QBrush brush(color);
setBrush(brush);
//可移动
setFlag(QGraphicsItem::ItemIsMovable);
//可选中
setFlag(QGraphicsItem::ItemIsSelectable);
}
重写 QGraphicsScene(场景)
myscene.h
#ifndef MYSCENE_H
#define MYSCENE_H
#include <QGraphicsScene>
#include <QObject>
#include "myitem.h"
class myScene : public QGraphicsScene
{
Q_OBJECT
public:
myScene(QObject *parent = 0);
signals:
void itemMoveSignal(myItem* item,const QPointF position);
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
private:
QGraphicsItem * m_Item;
QPointF m_oldPos;
};
#endif // MYSCENE_H
myscene.cpp
#include "myscene.h"
#include <QGraphicsSceneMouseEvent>
#include <QDebug>
myScene::myScene(QObject *parent)
{
m_Item = 0;
}
void myScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QPointF mousePos (event->buttonDownScenePos(Qt::LeftButton).x(),
event->buttonDownScenePos(Qt::LeftButton).y());
const QList<QGraphicsItem* >itemList = items(mousePos);
m_Item = itemList.isEmpty() ? 0 :itemList.first();
if(m_Item != 0 && event->button() == Qt::LeftButton)
m_oldPos = m_Item->pos();
QGraphicsScene::mousePressEvent(event);
}
void myScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if(m_Item != 0 && event->button() == Qt::LeftButton)
{
if(m_oldPos != m_Item->pos())
//发送位置移动的信号
emit itemMoveSignal(qgraphicsitem_cast<myItem*>(m_Item),m_oldPos);
m_Item = 0;
}
QGraphicsScene::mouseReleaseEvent(event);
}
下面重写的 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
【领QT开发教程学习资料,点击下方链接免费领取↓↓,先码住不迷路~】
点击→领取「链接」
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));//入栈操作
本文暂时没有评论,来添加一个吧(●'◡'●)