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

news2024/11/20 20:30:01
  • 用到的类:

    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 }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/29024.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C#上位机系列(3)—定时器和串口的介绍

本文是讲解C#.net平台的Winform框架下的第三个内容&#xff0c;手把手介绍上位机项目的创建方式以及一些写软件时常用的功能&#xff0c;讲解从零开始的每一个步骤。 本次介绍上位机中定时器的使用和串口的配置 定时器&#xff1a;每过一段设定好的时间进入执行函数&#xff…

SIMULIA现实仿真解决方案 SIMULIA仿真模拟应用程序

由 3DEXPERIENCE 平台提供技术支持&#xff0c;SIMULIA 可提供仿真模拟应用程序&#xff0c;这些应用程序使用户能够探究现实生活中产品、自然和生命的行为 SIMULIA 通过虚拟测试实现性能要求促进协作。其产品组合提供强大的工具&#xff0c;能够对采用V6设计的零件、组件和产…

敏捷开发失败的五个原因以及解决方案

作者&#xff1a;David Bevans , Mendix公司高级内容营销经理 敏捷开发是一个可以改变软件交付方式的框架且效果十分惊人&#xff0c;但鉴于需要反复不断规划、测试、集成以及其他进行中的开发方式&#xff0c;敏捷开发在某些情况下行不通。下文将对常见的敏捷开发失灵以及相应…

菁染料CY3/CY5/CY7标记链霉亲和素/胰岛素,CY3/CY5/CY7-Streptavidin/Insulin

产品名称&#xff1a;菁染料CY3/CY5/CY7标记链霉亲和素/胰岛素 英文名称&#xff1a;CY3/CY5/CY7-Streptavidin/Insulin 链霉亲和素(streptavidin下称SA)是与亲和素(avidin下称AV)有相似生物学特性的一种蛋白质&#xff0c;是streptomyces avidinii菌的分泌物&#xff0c;其分…

AotuDL中Linux环境下运行pix2pix-tensorflow的环境配置(tensorflow==1.8.0 python==3.6)

目录写在前面1. 租用实例时基础镜像的选择2. 配置环境3. 实验记录写在前面 &#x1f340;windows环境下运行&#xff1a;【用于图像修复、数据增强等】结合官方代码教程&#xff0c;在Windows 10下运行pix2pix-tensorflow&#xff08;tensorflow1.4.0 python3.6&#xff09; A…

【网站架构】服务器弹性伸缩不能全自动,实际如何追加服务器

大家好&#xff0c;欢迎来到停止重构的频道。 本期&#xff0c;我们讨论大型网站的伸缩性。 伸缩性指的是通过自动增减服务器数量以适应用户量或压力。 这些年&#xff0c;微服务、ServerLess、K8S等技术&#xff0c;都让人有一种服务器自动伸缩很容易实现的错觉。 其实&…

最短路径问题

目录 一、前言 二、算法讲解 1、Dijkstra--朴素算法&#xff1a;O(n * n) 2、Dijkstra--堆优化算法&#xff1a;O(mlogm) 3、Bellman_ford贝尔曼算法&#xff1a; O(n * m) 4、Spfa算法&#xff1a;O(n * m) 5、Spfa处理负环&#xff1a;O(n * m) 6、Floyd算法&#xf…

iOS 列表页面实时刷新解决方案

iOS 列表页面实时刷新解决方案 一、背景介绍 1.1 问题的出现 客户要求APP客户端每次切换Tab&#xff0c;都需要从服务器去获取最新的数据&#xff0c;所以每次切换Tab&#xff0c;客户端都会去主动刷新接口&#xff0c;以获取最新的数据。但是实际发现&#xff0c;每次切换T…

基于FPGA MIPS CPU设计学习(1)

关于什么是MIPS以及MIPS架构可参考文章: MIPS架构与指令简介 1 MIPS寄存器学习 MIPS寄存器详细解释如下: • 0 : 即 0: 即 0:

【Shell 脚本速成】04、Shell 脚本格式化输出与用户交互

目录 一、shell格式化输出 1、echo命令 案例演示&#xff1a; 2、输出颜色字体 3、综合案例 二、 用户交互 1、read命令 2、交互输入案例 计算机程序其实就是三步:输入、运算、输出&#xff0c;这个理论也适应于shell编程。 那么计算机是如何将信息按照比较舒服的格式输…

Unity - BRP管线关闭 - UpdateDepthTexture的绘制

最近一直忙着跟项目打杂。。。 比较少时间进修&#xff0c;充电。。。难受香菇 但是 unity 的踩坑经验倒是增加了不少&#xff08;还有很多坑的经验我都懒得写了&#xff0c;但是这些坑浪费查资料时间&#xff0c;还不如自己记下来&#xff0c;便于日后如果还有 BRP 项目的处理…

Neptune CHT-C助力零束打造智舱界王者

9月27日&#xff0c;上汽子品牌飞凡汽车的首款旗舰车型——飞凡R7刚一上市就牢牢吸引了众多视线&#xff0c;在了解了其配置后&#xff0c;用户纷纷称其为“智驾界卷王”。 飞凡R7搭载的RISING MAX 31巨幕&#xff0c;由中国品牌车型最大尺寸的43英寸宽幅真彩三联屏和全球首发量…

CSS的元素显示模式

元素显示模式是什么&#xff1f;&#xff1a; 由于网页中的标签非常多&#xff0c;在不同地方会用到不同类型的标签&#xff0c;了解他们的特点可以更好的布局我们的网页。 元素显示模式就是元素(标签)以什么方式进行显示&#xff0c;比如<div>独占一行&#xff0c;比如…

线索二叉树

目录 一、线索二叉树的类型定义 二、各种线索化的二叉树 三、中序线索二叉树的算法 完整代码&#xff1a; 一、线索二叉树的类型定义 typedef struct BTNode {ElemType data;//数据域struct BTNode* lchild;//左孩子或线索指针struct BTNode* rchild;//右孩子或线索指针int lt…

锐捷MPLS隧道单域实验配置

目录 配置AS100内的IGP路由协议 配置AS内的LDP 配置PE-PE的MP-BGP协议 在PE侧配置PE-CE的路由协议 在CE侧配置PE-CE的路由协议 将CE的路由重发布进MP-BGP中 将MP-BGP的路由重发布进CE中 MPLS隧道——单域基础理论讲解_静下心来敲木鱼的博客-CSDN博客_mpls隧道https://bl…

Python安装

一、官网下载 二、安装 找到下载的安装包&#xff0c;直接双击安装 三、设置环境变量 1、mac自带的python版本 2、修改为新下载的python3.11版本 1&#xff09;修改.bash_profile vi ~/.bash_profile 修改完成后&#xff0c;生效该文件&#xff1a;source ~/.bash_profile…

如何写出公众号爆文?分享你一份爆文写作秘籍

新媒体时代&#xff0c;想要产出一篇公众号爆文真的是难于上青天&#xff01;现在公众号内容同质化严重&#xff0c;如果你没有一些新颖的观点和真本事&#xff0c;是无法从成千上万的公众号中脱颖而出的&#xff01; 如何写出公众号爆文&#xff1f;为什么你看了那么多写作干货…

java--07 面向对象

altenter 文件名和public名保持一致 两个变量指向同一个对象的内存图&#xff1a;如果被一个对象更改 &#xff0c;另外一个对象跟着更改 垃圾回收机制&#xff1a; altenter &#xff1a;添加方法 ctraltt:添加循环 构造器 this关键字 ​​​​​​​ 封装&#x…

周志华机器学习(6):支持向量机

周志华机器学习&#xff08;6&#xff09;&#xff1a;支持向量机6 支持向量机6.1 间隔与支持向量6.2 对偶问题&#xff08;dual problem&#xff09;6.3 核函数6.4 软间隔与正则化基本是大段摘录加上一些自己的补充&#xff0c;去除了冗余的话。6 支持向量机 6.1 间隔与支持向…

实体店应该围绕什么核心来打造自己体系多模式多平台的生态

大家好&#xff0c;我是阿璋&#xff0c;阿璋时不时会发布一些创新的电商资讯&#xff0c;经过电商与疫情的反复摧残&#xff0c;实体商家的收益大不如从前&#xff0c;营业额一跌再跌&#xff0c;迎来实体寒潮&#xff0c;本期给大家分享一个实体店结合共享消费积分联盟广告生…