Qt绘图与图形视图之自定义图元实现拖拽、拉伸、旋转功能

往期回顾

Qt绘图与图形视图之移动鼠标手动绘制任意多边形的简单介绍-CSDN博客

Qt绘图与图形视图之场景、视图架构的简单介绍-CSDN博客

Qt绘图与图形视图之基本图元绘制的简单介绍-CSDN博客

 Qt绘图与图形视图之自定义图元实现拖拽、拉伸、旋转功能

一、最终效果

实现对自定义图元的旋转,拖拽、拉伸功能

二、主要思路

主要是三个需要处理的点,1、自己创建一个自定义图元,2、图元的旋转,拖拽、拉伸功能逻辑实现,3、鼠标样式改变 

1、主类的初始化

最开始在主类里进行的初始化

这个很简单,没什么好说的,记得顺序,是先视图,再是创建场景,创建图元并添加

ch88_CustomRectItem::ch88_CustomRectItem(QWidget *parent): QWidget(parent)
{ui.setupUi(this);QRect rect = ui.graphicsView->rect();// 创建场景QGraphicsScene* pScene = new QGraphicsScene(rect);// 视图里设置场景ui.graphicsView->setScene(pScene);// 创建自定义图元MyRectItem* pRectItem = new MyRectItem();// 场景添加图元pScene->addItem(pRectItem);
}

三、如何自定义图元

 1、设计思路

首先创建一个类继承自QGraphicsItem的,重写其父类的虚函数,重绘图案,本身调用函数可以重绘的图案有很多种的,重写鼠标事件,最后处理旋转的逻辑实现

2、新建C++类派生于QGraphicsItem

注意新建一个C++类,是需要直接派生于QGraphicsItem

class MyRectItem : public QObject, public QGraphicsItem
{Q_OBJECTpublic:MyRectItem(QGraphicsItem* parent = nullptr);~MyRectItem();// 必须重写该函数QRectF  boundingRect() const override;

这里为什么必须重写该函数? 

因为它本身是QGraphicsItem类的一个虚函数,如果不重写,那么MyRectItem类将也是一个虚函数类,无法创建对象的

virtual QRectF boundingRect() const = 0;

这个函数的作用是返回该图形项的边界矩形,即包围该图形项的最小矩形区域

QRectF MyRectItem::boundingRect() const
{QRectF boundingRectF = m_oldRectPolygon.boundingRect();return QRectF(boundingRectF.x() - 40, boundingRectF.y() - 40, boundingRectF.width() + 80, boundingRectF.height() + 80);
}

这个boundingRect()函数会返回一个比实际边界矩形更大一些的矩形区域,这样可以确保在绘制和碰撞检测时有足够的空间。

3、构造函数初始化

构造函数里先初始化各项值,设置矩形,此外还要设置矩形的大小和位置

MyRectItem::MyRectItem(QGraphicsItem* parent) :m_bResize(false),m_oldRect(0, 0, 200, 200),m_bRotate(false),m_RotateAngle(0),m_StateFlag(DEFAULT_FLAG)
{setRectSize(m_oldRect);//设置光标形状,手的形状setCursor(Qt::ArrowCursor);//设置图元是可移动的setFlags(QGraphicsItem::ItemIsMovable| QGraphicsItem::ItemIsSelectable| QGraphicsItem::ItemIsFocusable);m_pPointFofSmallRotateRect = new QPointF[4];SetRotate(0);
}

4、重写鼠标事件函数 

另外还需要重写一下这四个鼠标事件函数

注意参数类型,不再是QMouseEvent了,而是QGraphicsSceneMouseEvent 

    void paint(QPainter* painter,const QStyleOptionGraphicsItem* option,QWidget* widget) override;void mousePressEvent(QGraphicsSceneMouseEvent* event) override;void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override;void mouseReleaseEvent(QGraphicsSceneMouseEvent* event) override;

后面的几个思路:

4.1、绘制旋转后的矩形和圆形
4.2、 鼠标样式改变

主要是在鼠标按下事件里处理,毕竟确实是要鼠标按下了,样式才会改变,逻辑判断还是比较简单的,if-else语句先判断鼠标的位置,然后根据位置设置样式即可

4.3、鼠标移动的状态判断

鼠标移动这里的判断比较复杂,主要是根据m_StateFlag的状态来判断当前是旋转、移动矩形还是移动矩形的边线,然后再根据不同的状态进行不同的处理

1、如果是旋转矩形状态,根据鼠标位置计算旋转角度,并调用SetRotate函数设置旋转角度,然后调用setRectSize函数恢复矩形的位置和大小,并更新场景

2、如果是移动矩形状态(MOV_RECT),则根据鼠标移动的距离调用moveBy函数移动矩形,然后调用setRectSize函数恢复矩形的位置和大小,并更新场景 

3、如果是移动矩形的边线状态(MOV_LEFT_LINE、MOV_TOP_LINE、MOV_RIGHT_LINE、MOV_BOTTOM_LINE)则根据鼠标位置计算新的矩形边界,调用setRectSize函数设置新的矩形大小,并更新场景。 

4.4、鼠标松开后状态判断

主要就是判断是不是在旋转状态,如果是那么需要恢复状态为默认值,只要不是旋转,就不改变状态,所以迭代。

5、最难的旋转功能实现

旋转逻辑实现,拉伸拖拽功能都还好,比较难的是旋转功能的实现,毕竟旋转角度很多,而且旋转后每个点的位置坐标都将改变,需要一一获取

5.1、设置旋转角度
void MyRectItem::SetRotate(qreal RotateAngle, QPointF ptCenter)
{m_bRotate = true;if (ptCenter.x() == -999 && ptCenter.y() == -999){m_RotateCenter = QPointF(m_oldRect.x() + m_oldRect.width() / 2, m_oldRect.y() + m_oldRect.height() / 2);}else{m_RotateCenter = ptCenter;}m_RotateAngle = RotateAngle;this->update();
}
5.2、获取旋转后的点
QPointF MyRectItem::getRotatePoint(QPointF ptCenter, QPointF ptIn, qreal angle)
{double dx = ptCenter.x();double dy = ptCenter.y();double x = ptIn.x();double y = ptIn.y();double xx, yy;xx = (x - dx) * cos(angle * M_PI / 180) - (y - dy) * sin(angle * M_PI / 180) + dx;yy = (x - dx) * sin(angle * M_PI / 180) + (y - dy) * cos(angle * M_PI / 180) + dy;return QPointF(xx, yy);
}
5.3、获取旋转后的多个点
QList<QPointF> MyRectItem::getRotatePoints(QPointF ptCenter, QList<QPointF> ptIns, qreal angle)
{QList<QPointF> lstPt;for (int i = 0; i < ptIns.count(); i++){lstPt.append(getRotatePoint(ptCenter, ptIns.at(i), angle));}return lstPt;
}
5.4、矩形旋转后返回多边形
QPolygonF MyRectItem::getRotatePolygonFromRect(QPointF ptCenter, QRectF rectIn, qreal angle)
{QVector<QPointF> vpt;QPointF pf = getRotatePoint(ptCenter, rectIn.topLeft(), angle);vpt.append(pf);pf = getRotatePoint(ptCenter, rectIn.topRight(), angle);vpt.append(pf);pf = getRotatePoint(ptCenter, rectIn.bottomRight(), angle);vpt.append(pf);pf = getRotatePoint(ptCenter, rectIn.bottomLeft(), angle);vpt.append(pf);pf = getRotatePoint(ptCenter, rectIn.topLeft(), angle);vpt.append(pf);return QPolygonF(vpt);
}
5.5、实时获取旋转时矩形正上方的标记

以上就是Qt里自定义图元实现拖拽、拉伸、旋转功能的简单介绍。

都看到这里了,点个赞再走呗朋友~

加油吧,预祝大家变得更强!

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

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

相关文章

应用层协议了解

一 HTTP前置知识 这篇博客会有点长&#xff0c;但对我来说非常有意义&#xff0c;这是我从一无所知到理解网络的重大突破&#xff0c;在前两个月我对网络非常恐惧&#xff0c;还十分不理解什么是网络&#xff0c;什么是协议。接下来先介绍几个概念。 1 流量 我们把数据给别人&…

GitHub Desktop进行汉化

第一步下载github桌面版 官网&#xff1a;安装 GitHub Desktop - GitHub 文档 历史版本&#xff1a;https://github.cn.uptodown.com/windows/versions 本期下载版本3.3.11进行汉化&#xff0c;最新版不一定稳定。 网站打不开的可自取&#xff1a; 3.3.11版本安装包链接&a…

【论文笔记】Language Models are Few-Shot Learners B部分

Language Models are Few-Shot Learners B 部分 回顾一下第一代 GPT-1 &#xff1a; 设计思路是 “海量无标记文本进行无监督预训练少量有标签文本有监督微调” 范式&#xff1b;模型架构是基于 Transformer 的叠加解码器&#xff08;掩码自注意力机制、残差、Layernorm&#…

排序算法:插入、希尔、选择、推排、冒泡、快速、归并排序

排序算法 目录 前言 一、排序的概念 1.1排序的概念 1.2 常见的排序算法 二、常见排序算法的实现 2.1 插入排序 2.2 希尔排序 2.3 选择排序 2.4 堆排序 2.5 冒泡排序 2.6 快速排序 2.6.1 hoare版本 2.6.2 前后指针版本 2.6.3 非递归版本 2.7 归并排序 归并排序 2.8 计数排序 三、…

【mysql】mysql中的数据类型知多少?

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

在VMware中如何快速克隆出一台虚拟机

鉴于经常需要使用新开虚拟机出来给开发团队用于测试部署&#xff0c;之前没有克隆功能之前都是需要一台装一个操作系统&#xff0c;无论是linux、windows server版或 windows 10 版&#xff0c;整个安装过程下来还是要一个来小时。后来做了装了十多次以后&#xff0c;想着试一下…

《微服务设计》读书笔记

此为阅读纽曼《微服务设计》一书后总结的读书笔记&#xff0c;点此处下载PDF文档。 一、微服务的概念 微服务&#xff08;或称微服务架构&#xff09;是一种云原生架构方法&#xff0c;其核心思想在于将单个应用拆分为众多 小型、松散耦合的服务&#xff0c;服务之间均通过网…

利用Triple U.Net结构对冷冻切片HE染色组织学图像进行核实例分割

利用Triple U.Net结构对冷冻切片H&E染色组织学图像进行核实例分割 摘要IntroductionRelated WorksDatasetProposed MethodologyDataset PreparationSegmentation BranchLoss FunctionWatershed Algorithm Nuclei Instance Segmentation of Cryosectioned H&E Stained H…

基于Springboot的校园博客系统

基于SpringbootVue的校园博客系统 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringbootMybatis工具&#xff1a;IDEA、Maven、Navicat 系统展示 用户登录 首页 文章信息 系统公告 后台登录 后台首页 博主管理 文章分类管理 文章信息管理 举报投诉管…

网络编程——TCP

socket socket类型 流式套接字(SOCK_STREAM) TCP 提供了一个面向连接、可靠的数据传输服务&#xff0c;数据无差错、无重复、无丢失、无失序的发送且按发送顺序接收。内设置流量控制&#xff0c;避免数据流淹没慢的接收方。数据被看作是字节流&#xff0c;无长度限制。 数据报…

IDEA新版本创建Spring项目只能勾选17和21却无法使用Java8的完美解决方案

想创建一个springboot的项目&#xff0c;使用Spring Initializr创建项目时&#xff0c;发现版本只有17&#xff5e;21&#xff0c;无法选择Java8。 我们知道IDEA页面创建Spring项目&#xff0c;其实是访问spring initializr去创建项目。我们可以通过阿里云国服间接创建Spring项…

【UE5】动态播放媒体

最近项目中有一个需求&#xff0c;需要将场景中的42块屏幕都显示媒体内容&#xff0c;想着如果每一块屏幕都创建一个MediaPlayer资产、一个MediaSource资产、一个MediaTexture资产及创建对应的Material&#xff0c;就是4*42168个资产需要维护了&#xff0c;所以想着就全部采用动…

Python并发编程:揭开多线程与异步编程的神秘面纱

第一章&#xff1a;并发编程导论 1.1 并发与并行概念解析 1.1.1 并发性与并行性的区别 想象一下繁忙的厨房中多位厨师同时准备不同的菜肴——即使他们共享有限的空间和资源&#xff0c;也能协同工作&#xff0c;这就是并发性的一个生动比喻。并发性意味着多个任务在同一时间…

秋招后端开发面试题 - Java语言基础(下)

目录 Java基础下前言面试题toString() 、String.valueof()、(String)&#xff1f;hashCode() 方法&#xff1f;hashCode 和 equals 方法判断两个对象是否相等&#xff1f;为什么重写 equals 时必须重写 hashCode 方法&#xff1f;String、StringBuffer、StringBuilder?String …

【Qt】控件的核心属性

1 &#x1f351;控件概述&#x1f351; Widget 是 Qt 中的核⼼概念. 英⽂原义是 “⼩部件”, 我们此处也把它翻译为 “控件” .控件是构成⼀个图形化界⾯的基本要素。 Qt 作为⼀个成熟的 GUI 开发框架, 内置了⼤量的常⽤控件。这⼀点在 Qt Designer 中就可以看到端倪&#xf…

学习STM32第二十天

低功耗编程 一、修改主频 STM32F4xx系列主频为168MHz&#xff0c;当板载8MHz晶振时&#xff0c;系统时钟HCLK满足公式 H C L K H S E P L L N P L L M P L L P HCLK \frac{HSE \times PLLN}{PLLM \times PLLP} HCLKPLLMPLLPHSEPLLN​&#xff0c;在文件stm32f4xx.h中可修…

Flutter应用开发-几种保存简单配置的方式

文章目录 简单配置保存的几种方式使用 shared_preferences 插件优点缺点 使用 hive 插件优点 缺点使用文件存储&#xff1a;优点缺点 简单配置保存的几种方式 在 Flutter 开发的 Android 应用中&#xff0c;保存应用配置并下次启动时读取&#xff0c;有以下几种比较合适的方式…

LabVIEW 2024安装教程(附免费安装包资源)

鼠标右击软件压缩包&#xff0c;选择“解压到LabVIEW.2024”。 返回解压后的文件夹&#xff0c;鼠标右击“ni_labview-2024”选择“装载”。 鼠标右击“Install”选择“以管理员身份运行”。 点击“我接受上述2条许可协议”&#xff0c;然后点击“下一步”。 点击“下一步”。 …

asp.net结课作业中遇到的问题解决1

作业要求 实现增删改查导出基本功能。 1、如何设置使得某个背景就是一整个而不是无限填充或者是这个图片的某一部分。 这就要求在设置这一块的时候&#xff0c;长和宽按照背景图片的大小进行设置&#xff0c;比如&#xff1a; 如果&#xff0c;图片的大小不符合你的要求&am…

北大字节提出VAR新范式,GPT超越扩散、视觉生成Scaling Law

前言 来自北京大学和字节跳动的研究团队&#xff0c;提出了一种名为"Visual AutoRegressive (VAR) Modeling"的全新视觉生成范式。VAR 重新定义了图像的自回归学习过程&#xff0c;从而使得GPT风格的自回归模型首次超越扩散模型&#xff0c;在图像生成质量、速度和可…