zl程序教程

您现在的位置是:首页 >  工具

当前栏目

Qt QUndoStack、QUndoCommand(实现撤回和回撤)

Qt 实现 撤回
2023-09-14 09:05:12 时间

用到的类:

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)写的:

CSDN QT开发技术文推荐:Qt开发必备技术栈学习路线和资料

重写 QGraphicsPolygonItem (方块)

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() 方法

 CSDN QT开发技术文推荐:Qt开发-学习路线+资料包

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 }

  CSDN QT开发技术文推荐:Qt开发-学习路线+资料包

主界面

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));//入栈操作

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QT嵌入式开发,Quick模块等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓