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

news2024/11/25 10:44:55

往期回顾

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_OBJECT

public:
    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.coloradmin.cn/o/1632571.html

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

相关文章

Agent AI智能体在未来,一定与你我密不可分

随着Agent AI智能体的逐渐成熟&#xff0c;人工智能应用的不断深入与拓展&#xff0c;相信在不久的将来&#xff0c;他与你我的生活一定是密不可分的。 目录 ​编辑 1 Agent AI智能体是什么&#xff1f; 2 Agent AI在语言处理方面的能力 2.1 情感分析示例 2.2 文本分类任…

Tetra Pak利乐中试工厂仿真 - 工艺开发、配方开发和无菌灌装的试验

此模型是基于速率的模型&#xff0c;使用Rate模块库中的离散速率模块和Item模块库中的离散事件模块。速率模块库位于ExtendSim Pro中。 利乐中试工厂&#xff08;得克萨斯州丹顿&#xff09;进行工艺开发、配方开发和无菌灌装的试验。它还对新的加工和灌装设备进行内部测试。该…

Colab用例与Gemma快速上手指南:如何在Colab和Kaggle上有效地运用Gemma模型进行机器学习任务

&#x1f42f; Colab用例与Gemma快速上手指南 &#x1f680; 文章目录 &#x1f42f; Colab用例与Gemma快速上手指南 &#x1f680;摘要引言正文&#x1f4dd; **基础使用&#xff1a;Gemma快速上手**环境设置和模型加载安装必要的库加载Gemma模型 推理示例 &#x1f6e0; **Ge…

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

目录 Java基础上前言面试题Java 语言的特点JVM JDK JRE什么是跨平台性&#xff1f;原理是什么&#xff1f;什么是字节码?采用字节码的好处是什么?Java 和 C 的区别&#xff1f;注释&#xff1f;关键字关键字 instanceof类型转换关键字 this 和 super关键字 final finally fin…

【CGALDotNet】CGAL的C#封装(C#调用编译好的CGAL的dll)

介绍 开源项目出处&#xff08;两个模块&#xff09;&#xff1a; 链接1&#xff1a;https://github.com/Scrawk/CGALDotNet/tree/master?tabreadme-ov-file 链接2&#xff1a;https://github.com/Scrawk/CGALDotNetGeometry 该项目提供了编译的、封装相关接口后的CGAL库&am…

纯js对比excel小工具

如何使用JavaScript和xlsx.js实现Excel文件对比&#xff1a;实战指南 在日常办公或数据分析工作中&#xff0c;我们经常需要比较两个Excel文件中的数据差异。手动对比不仅耗时费力&#xff0c;还容易出错。本文将带你通过一个简单的网页应用&#xff0c;利用JavaScript和开源库…

Spring AI聊天功能开发

一、引入依赖 继承父版本的springboot依赖&#xff0c;最好是比较新的依赖。 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.4</version><relativePat…

transformer上手(10)—— 文本摘要任务

文本摘要是一个 Seq2Seq 任务&#xff0c;尽可能保留文本语义的情况下将长文本压缩为短文本。 文本摘要可以看作是将长文本“翻译”为捕获关键信息的短文本&#xff0c;因此大部分文本摘要模型同样采用 Encoder-Decoder 框架。当然&#xff0c;也有一些非 Encoder-Decoder 框架…

低代码技术在构建质量管理系统中的应用与优势

引言 在当今快节奏的商业环境中&#xff0c;高效的质量管理系统对于组织的成功至关重要。质量管理系统帮助组织确保产品或服务符合客户的期望、符合法规标准&#xff0c;并持续改进以满足不断变化的需求。与此同时&#xff0c;随着技术的不断进步&#xff0c;低代码技术作为一…

Linux系统编程---线程池并发服务器

模型原理分析&#xff1a; 线程池的关键优势在于它减少了每次任务执行时创建和销毁线程的开销 线程池的组成主要分为 3 个部分&#xff0c;这三部分配合工作就可以得到一个完整的线程池&#xff1a; 1. 任务队列&#xff0c;存储需要处理的任务&#xff0c;由工作的线程来处理…

python代码实现kmeans对鸢尾花聚类

导入第三方库和模型 from sklearn import datasets import numpy as np import matplotlib.pyplot as plt from sklearn.cluster import KMeans2、创建画图函数 def draw_result(train_x, labels, cents, title):n_clusters np.unique(labels).shape[0]#获取类别个数color …

esp32s3使用psram后音频播报不了的问题解决记录

idf.py menuconfig开启psram后会报错 提示需要打补丁&#xff1a; 根据提示切换到IDF_PATH目录&#xff0c;然后执行git apply %ADF_PATH%/ida_patches/idf5.0_freertos.patch打补丁。 再次编译提示如下错误&#xff1a; assert failed: spi_flash_disable_interrupts_cach…

嵌入式学习,方法、交流很重要

关注、星标公众号&#xff0c;直达精彩内容 ID&#xff1a;技术让梦想更伟大 整理&#xff1a;李肖遥 Who Am I 大家好&#xff0c;我是「逍遥的小蜜圈」星球的星主&#xff0c;如果大家关注我早一点&#xff0c;一定看了我的简单的自我介绍&#xff0c;关于我 — 聊聊自己的经…

【Python网络爬虫】python爬虫用正则表达式进行数据清洗与处理

&#x1f517; 运行环境&#xff1a;PYTHON &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 #### 防伪水印——左手の明天 #### &#x1f497; 大家好&#x1f917;&#x1f91…

QT学习篇—qt软件安装

qt下载网址http://download.qt.io/new_archive/qt/ QT官网Qt | Tools for Each Stage of Software Development LifecycleAll the essential Qt tools for all stages of Software Development Lifecycle: planning, design, development, testing, and deployment.https:…

CSS样式特异性5层次详解

你好&#xff0c;我是云桃桃。 一个希望帮助更多朋友快速入门 WEB 前端的程序媛。 云桃桃-大专生&#xff0c;一枚程序媛&#xff0c;感谢关注。回复 “前端基础题”&#xff0c;可免费获得前端基础 100 题汇总&#xff0c;回复 “前端工具”&#xff0c;可获取 Web 开发工具合…

FANUC机器人SOCKET断开KAREL程序编写

一、添加一个.KL文件创建编辑断开指令 添加一个KL文件用来创建karel程序中socket断开指令 二、断开连接程序karel代码 PROGRAM SOC_DIS %COMMENT SOCKET断开 %INCLUDE klevccdf VAR str_input,str_val : STRING[20] status,data_type,int_val : INTEGER rel_val : REALBEGING…

全球首发!龙蜥社区助力 Intel SPR 加速器上云

编者按&#xff1a;云原生平台下芯片的竞争力日渐增强&#xff0c;加速器如何在赛道上体现竞争力。龙蜥社区开发者、阿里云高级研发工程师易兴睿介绍运用龙蜥操作系统提供的解决方案&#xff0c;依靠 Intel SPR 平台专用硬件加速器&#xff0c;实现云原生场景下 Envoy 网关加速…

微信小程序 request 配置了服务器域名后 发布体验版无法访问

问题描述 在微信小程序公众平台配置了测试服务器域名后&#xff0c;发布了体验版进行测试&#xff0c;发现网络请求不通&#xff0c;打开调试也依然无法访问。 解决步骤&#xff1a; 1.首先根据小程序文档网络模块的使用说明&#xff0c;一步步排查域名证书是否符合规范&…

Llama3 mac本地部署教程

1.下载的软件清单&#xff1a; ollama下载&#xff1a; Download Ollama on macOS nodejs下载&#xff1a; Node.js — Download Node.js 2.安装 安装Ollama 下载之后打开&#xff0c;直接点击Next以及Install安装ollama到命令行。安装完成后界面上会提示ollama run llam…