【QT继承QLabel实现绘制矩形、椭圆、直线、多边形功能,并且支持修改大小,移动位置,复制,粘贴,删除功能】

文章目录

    • 介绍
    • 绘制一个矩形(椭圆)roi
    • 绘制一个多边形roi
    • 对矩形roi的缩放:
    • 对多边形rio的缩放(移动点的位置)

介绍

绘制矩形,椭圆,直线实际用的都是是同一个思路:鼠标第一次点击就确定了本次绘制的矩形(椭圆,直线)的位置,然后拖动鼠标生成矩形(椭圆,直线),最后释放鼠标,矩形(椭圆,直线)就绘制完成了。而多边形不同,绘制多边形是一种离散的操作,多边形是由多个离散的点组成,靠的是鼠标点击绘制,而不是拖动绘制,因此文章只介绍矩形的多边形的绘制方法。
项目运行效果
代码地址:MyLabel-ROI

绘制一个矩形(椭圆)roi

继承QLabel,重写 paintEvent,mouseMoveEvent,mousePressEvent方法。

绘制矩形(椭圆)roi的思路是:设置鼠标点击的位置为矩形roi的左上角(mousePressEvent)—>鼠标在移动的过程中更新矩形roi的右下角(mouseMoveEvent)—>更新QLabel上的内容(paintEvent)。

void MyLabel::paintEvent(QPaintEvent *event){QLabel::paintEvent(event);QPainter* painter = new QPainter(this);painter->drawRect(rect);//绘制以rect为外接矩形的椭圆//painter->drawEllipse(rect);painter->end();	//调用QLabel的update方法,刷新内容
}
void MyLabel::mouseMoveEvent(QMouseEvent *event){rect.setBottomRight(event->pos());update();
}	
void MyLabel::mousePressEvent(QMouseEvent *event){rect.setTopLeft(event->position());
}

这样,就能绘制一个矩形(椭圆)roi了。绘制直线的过程也符合上述逻辑:首先,设置鼠标点击的位置为线的第一个点;然后,在鼠标移动的过程中,不断地更新线的第二个点;最后,再调用update方法更新即可。
在这里插入图片描述

绘制一个多边形roi

绘制多边形roi的思路与上述的矩形,椭圆,直线就不一样。由于多边形是离散的多个点,我们就需要使用一个容器来存储这些点。实际上,在QT实现的QPolygon类中,也是用一个QList链表来存储这些节点。
在这里插入图片描述
绘制多边形roi的思路是:用链表记录鼠标每次点击的位置(mousePressEvent)---->绘制多边形的中的点和线段(paintEvent),注意在绘制完之前,多边形roi不是闭合的。

void MyLabel::paintEvent(QPaintEvent *event){QLabel::paintEvent(event);QPainter* painter = new QPainter(this);QPolygonF polygon;for (int i = 0; i < myPolygon.length(); i++)   polygon.append(myPolygon[i]);painter->drawPolyline(polygon);painter->drawPoints(polygon);painter->end();
}
void MyLabel::mousePressEvent(QMouseEvent *event){if(event->button()==Qt::LeftButton)myPolygon.append(event->pos());else if(event->button()==Qt::RightButton){//多边形绘制完毕}
}

在这里插入图片描述

对矩形roi的缩放:

当鼠标在以下两个范围时,就可以对roi的大小进行缩放

  1. 距离矩形roi顶点周围CORPADDING像素大小
  2. 在矩形的边内外EDGPADDING像素大小

在这里插入图片描述
由于拖动不同的边和不同的顶点,矩形的缩放行为也不一样(往左拖动左边,矩形就应该向左放大;往右拖动左边,矩形就应该向右缩小)。为了清楚当前是拖动矩形roi的那条边,那个顶点,就需要引入方向枚举变量。

enum EmDirection{DIR_TOP = 0,	//鼠标位于矩形的左边DIR_BOTTOM,		//鼠标位于矩形的右边DIR_LEFT,	DIR_RIGHT,DIR_LEFTTOP,	//鼠标位于矩形的左上方顶点DIR_LEFTBOTTOM,	//鼠标位于矩形的左下方顶点DIR_RIGHTTOP,DIR_RIGHTBOTTOM,DIR_MIDDLE, //鼠标位于矩形ROI区域中DIR_NONE	//鼠标距离roi较远的位置
};

判断鼠标当前拖动的方向:

EmDirection rectRegion(QRectF rect, QPointF point){int mouseX = point.x();int mouseY = point.y();QPointF roiTopLeft = rect.topLeft();QPointF roiBottomRight = rect.bottomRight();EmDirection dir = DIR_NONE;if (mouseX <= roiTopLeft.x() + CORPADDING && mouseX >= roiTopLeft.x() && mouseY <= roiTopLeft.y() + CORPADDING && mouseY >= roiTopLeft.y()){   //左上角this->setCursor(Qt::SizeFDiagCursor);dir = DIR_LEFTTOP;}//接着再判断  右上角,左下角,右下角 的情况else if (mouseX >= roiBottomRight.x() - EDGPADDING && mouseX <= roiBottomRight.x() && mouseY >= roiTopLeft.y() && mouseY <= roiBottomRight.y()){   //右边this->setCursor(Qt::SizeHorCursor);dir = DIR_RIGHT;}//再判断 上边,下边,左边 的情况else if (mouseY <= roiTopLeft.y() + EDGPADDING && mouseY >= roiTopLeft.y() && mouseX >= roiTopLeft.x() && mouseX <= roiBottomRight.x())else if(rect.contains(point))    {	//内部dir = DIR_MIDDLE;}else{dir = DIR_NONE;}return dir;
}

在获取了缩放的方向之后,就可以进行缩放操作了:

void scaleRect(QRectF rect, QPoint mousePoint){switch (this->emCurDir) {case DIR_LEFT:	//向左缩放if(mousePoint.x()>=0)   rect.setLeft(mousePoint.x());break;case DIR_RIGHT:	//向右缩放if(mousePoint.x()<=MUL_LABEL_WIDTH) rect.setRight(mousePoint.x());break;case DIR_TOP:	//向上缩放if(mousePoint.y()>=0)   rect.setTop(mousePoint.y());break;case DIR_BOTTOM:	//向下缩放if(mousePoint.y()<=MUL_LABEL_HEIGHT)    rect.setBottom(mousePoint.y());break;case DIR_LEFTTOP:	//拖动矩形的左上顶点if(mousePoint.x()<=0 && mousePoint.y()<=0){	//这些代码是做了边界处理,限制了roi只能在QLabel内rect.setTopLeft(QPoint(0, 0));}else if(mousePoint.x()<=0){rect.setTopLeft(QPoint(0, mousePoint.y()));}else if(mousePoint.y()<=0){rect.setTopLeft(QPoint(mousePoint.x(), 0));}else{rect.setTopLeft(mousePoint);}break;case DIR_LEFTBOTTOM:	//拖动矩形的右下顶点if(mousePoint.x()<=0 && mousePoint.y()>=MUL_LABEL_HEIGHT){rect.setBottomLeft(QPoint(0, MUL_LABEL_HEIGHT));}else if(mousePoint.x()<=0){rect.setBottomLeft(QPoint(0, mousePoint.y()));}else if(mousePoint.y()>=MUL_LABEL_HEIGHT){rect.setBottomLeft(QPoint(mousePoint.x(), MUL_LABEL_HEIGHT));}else{rect.setBottomLeft(mousePoint);}break;case DIR_RIGHTTOP:	//拖动矩形的右上顶点if(mousePoint.x()>=MUL_LABEL_WIDTH && mousePoint.y()<=0){rect.setTopRight(QPoint(MUL_LABEL_WIDTH, 0));}else if(mousePoint.x()>=MUL_LABEL_WIDTH){rect.setTopRight(QPoint(MUL_LABEL_WIDTH, mousePoint.y()));}else if(mousePoint.y()<=0){rect.setTopRight(QPoint(mousePoint.x(), 0));}else{rect.setTopRight(mousePoint);}break;case DIR_RIGHTBOTTOM:	//拖动矩形的右下顶点if(mousePoint.x()>=MUL_LABEL_WIDTH && mousePoint.y()>=MUL_LABEL_WIDTH){rect.setBottomRight(QPoint(MUL_LABEL_WIDTH, MUL_LABEL_HEIGHT));}else if(mousePoint.x()>=MUL_LABEL_WIDTH){rect.setBottomRight(QPoint(MUL_LABEL_WIDTH, mousePoint.y()));}else if(mousePoint.y()>=MUL_LABEL_HEIGHT){rect.setBottomRight(QPoint(mousePoint.x(), MUL_LABEL_HEIGHT));}else{rect.setBottomRight(mousePoint);}break;default:qDebug()<<"scale default";break;}//限制最小的缩放if(rect.width()<MIN_SCALE_WIDTH || rect.height()<MIN_SCALE_HEIGHT){return;}this->rect = rect;  //更新ROI矩形
}

对椭圆roi的缩放实际上就是对其外接矩形缩放,原理和矩形roi一样,这里就不再介绍。

对多边形rio的缩放(移动点的位置)

如果鼠标在多边形点周围CORPADDING像素范围的大小,那么鼠标就可以拖动该顶点,以修改多边形的形状和大小
在这里插入图片描述
当找到了拖动的那个点后,再进行拖动,就能缩放多边形roi了。

void ROIAndVertex::scalePolygon(QPolygonF polygonF, QPoint point){for(int i=0; i<polygonF.size(); i++){QPointF p = polygonF[i];QRectF rectF = QRectF(p.x()-CORPADDING, p.y()-CORPADDING, 2*CORPADDING, 2*CORPADDING);if(rectF.contains(point)){ele->polygon[i] = point;return;}}
}

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

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

相关文章

3.0 Disruptor的使用介绍(一)

Disruptor: 其官网定义为&#xff1a;“A High Performance Inter-Thread Messaging Library”&#xff0c;即&#xff1a;线程间的高性能消息框架&#xff0c;与Labview的生产者、消费者模型很相似。 其组成部分比较多&#xff0c;先介绍几个常用的概念&#xff1a; …

ubuntu 2204键盘按键映射修改

键盘的按键和实际输出不一致&#xff0c;可以通过以下方法重新修改按键keycode. 1.在终端执行如下命令&#xff1a; xev -event keyboard 上边64是alt_l&#xff0c;但是键盘上对应的super(windows)。 2.vim /usr/share/X11/xkb/keycodes/evdev //<LALT> 64; 注释&l…

【Linux】System V共享内存:零拷贝加速进程通信!

引言 本文深入探讨System V IPC中的共享内存技术&#xff0c;涵盖其原理、操作步骤、实现细节及与其他IPC机制的关系&#xff0c;助力读者全面掌握这一高效进程间通信方式。 &#x1f4dd; 文章总结&#xff1a; 共享内存原理 System V共享内存通过让多个进程共享同一物理内存区…

UE4学习笔记 FPS游戏制作31 显示计分板

一 制作计分板 创建一个RankPanel的UI蓝图 在蓝图里拖入如下物体 覆层&#xff08;layout&#xff09;&#xff1a;让子物体跟随自己缩放&#xff0c;子物体需要设置为拉伸模式&#xff0c;有点类似于的panel&#xff0c;本身只是一个容器 调整各个物体 覆层&#xff1a; 锚…

如何在Linux CentOS上安装和配置Redis

如何在Linux CentOS上安装和配置Redis 大家好&#xff0c;我是曾续缘。欢迎来到本教程&#xff01;今天我将向您介绍在Linux CentOS上安装和配置Redis的详细步骤。Redis是一个高性能的键值存储系统&#xff0c;常用于缓存、消息队列和数据持久化等应用场景。让我们一起开始吧&…

Realsense-D400 系列手动曝光控制

文章目录 1、曝光 & 增益2、曝光 & 帧率3、调参 & 加载4、高级控制选项5、官方文档参考小结 1、曝光 & 增益 曝光exposure&#xff1a;英特尔 RealSense D400设备模组中的可见光 RGB 传感器和红外左右目传感器具有单独的曝光控制&#xff0c;对于双目红外&…

最大异或对 The XOR Largest Pair

题目来自洛谷网站&#xff1a; 思路&#xff1a; 两个循环时间复杂度太高了&#xff0c;会超时。 我们可以先将读入的数字&#xff0c;插入到字典树中&#xff0c;从高位到低位。对每个数查询的时候&#xff0c;题目要求是最大的异或对&#xff0c;所以我们选择相反的路径&am…

探索 curl ipinfo.io:从命令行获取你的网络身份卡!!!

&#x1f310; 探索 curl ipinfo.io&#xff1a;从命令行获取你的网络身份卡 &#x1faaa; &#x1f680; 简介&#xff1a;为什么需要 curl ipinfo.io&#xff1f; 当你在调试网络服务、排查访问限制或开发基于地理位置的应用时&#xff0c;公网 IP 信息就像一张网络身份证。…

Chrome(Google) 浏览器安装Vue2、Vue3 Devtools插件方法

方式一&#xff1a;本地下载安装 步骤一&#xff1a;下载 网站:极简插件官网_Chrome插件下载_Chrome浏览器应用商店 步骤二&#xff1a;下载后解压,并拖入浏览器扩展页面&#xff0c;安装插件后&#xff0c;重启浏览器。 步骤三&#xff1a;查看是否安装成功 方式二&#x…

树莓派超全系列文档--(7)RaspberryOS播放音频和视频

播放音频和视频 播放音频和视频VLC 媒体播放器vlc GUIvlc CLI使用 cvlc 在没有图形用户界面的情况下播放媒体 在 Raspberry Pi OS Lite 上播放音频和视频指定音频输出设备指定视频输出设备同时指定音频和视频输出设备提高数据流播放性能 文章来源&#xff1a; http://raspberr…

MySQL 8.0.41安装教程(附安装包)mysql8.0.41图文详细安装教程

文章目录 前言一、MySQL 8.0.41下载安装包二、MySQL 8.0.41安装教程1.启动安装程序2.选择安装模式3.选定安装组件4.确认安装设置5.执行安装操作6.安装进行中7.设置数据库密码8.继续点击下一步9.执行配置操作10.完成配置11. 再次点击下一步12.结束安装向导 三、MySQL 8.0.41配置…

centos7 linux VMware虚拟机新添加的网卡,能看到网卡名称,但是看不到网卡的配置文件

问题现象&#xff1a;VMware虚拟机新添加的网卡&#xff0c;能看到网卡&#xff0c;但是看不到网卡的配置文件 解决方案&#xff1a; nmcli connection show nmcli connection add con-name ens36 ifname ens36 type ethernet #创建一个网卡连接配置文件&#xff0c;这里con…

【LVS】负载均衡群集部署(DR模式)

部署前IP分配 DR服务器&#xff1a;192.168.166.101 vip&#xff1a;192.168.166.100 Web服务器1&#xff1a;192.168.166.104 vip&#xff1a;192.168.166.100 Web服务器2&#xff1a;192.168.166.107 vip&#xff1a;192.168.166.100 NFS服务器&#xff1a;192.168.166.108 …

服务器与客户端通讯测试

服务器与客户端通讯测试 1 服务器与客户端通讯建立1.1 Main函数1.2 开启服务器1.3 客户端连接服务器1.4 扩展类 2 测试过程2.1 测试12.2 测试22.3 测试32.4 测试4 3 测试总结 测试服务器与客户端通讯时&#xff0c;发现数据丢包问题非常严重&#xff0c;肯定是自己的问题不会是…

Next.js 中间件鉴权绕过漏洞 (CVE-2025-29927) 复现利用与原理分析

免责声明 本文所述漏洞复现方法仅供安全研究及授权测试使用&#xff1b; 任何个人/组织须在合法合规前提下实施&#xff0c;严禁用于非法目的&#xff1b; 作者不对任何滥用行为及后果负责&#xff0c;如发现新漏洞请及时联系厂商并遵循漏洞披露规则。 漏洞原理 Next.js 是一个…

基于STC89C51的太阳自动跟踪系统的设计与实现—单片机控制步进电机实现太阳跟踪控制(仿真+程序+原理图+PCB+文档)

摘 要 随着我国经济的飞速发展&#xff0c;促使各种能源使用入不敷出&#xff0c;尤其是最主要的能源&#xff0c;煤炭石油资源不断消耗与短缺&#xff0c;因此人类寻找其他替代能源的脚步正在加快。而太阳能则具有无污染﹑可再生﹑储量大等优点&#xff0c;且分布范围广&…

在 Mermaid 流程图里“驯服”quot;的魔法指南!!!

&#x1f409; 在 Mermaid 流程图里“驯服”"的魔法指南 在使用 Mermaid 画流程图时&#xff0c;是不是经常遇到想秀一波 &quot; 却被它“反杀”的情况&#xff1f;&#x1f3af; 今天就来教大家如何在这头代码野兽的嘴里&#xff0c;抢回我们的双引号实体编码&#…

SQL语句---DDL

文章目录 1、SQL语句2、DDL2.1 数据库的操作显示当前的数据库创建数据库指定编码删除数据库切换当前数据库 2.2 数据表的操作显示表创建表显示表结构修改表添加新的字段删除原有字段 修改原有字段删除数据表 2.3 Mysql数据库中常用的数据类型 1、SQL语句 结构化查询语句&#…

界面控件Telerik和Kendo UI 2025 Q1亮点——AI集成与数据可视化

Telerik DevCraft包含一个完整的产品栈来构建您下一个Web、移动和桌面应用程序。它使用HTML和每个.NET平台的UI库&#xff0c;加快开发速度。Telerik DevCraft提供完整的工具箱&#xff0c;用于构建现代和面向未来的业务应用程序&#xff0c;目前提供UI for ASP.NET MVC、Kendo…

信源的分类及数学模型

信源的分类及数学模型 按照信源发出的时间和消息分布分为离散信源和连续信源 按照信源发出符号之间的关系分为无记忆信源和有记忆信源 单符号离散信源&#xff08;一维离散信源&#xff09; 信源输出的消息数有限或可数&#xff0c;且每次只输出符号集的一个消息 样本空间&…