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

往期回顾

【QT进阶】Qt线程与并发之QtConcurrent返回值与run方法的参数说明-CSDN博客

Qt绘图与图形视图之绘图技术知识点的简单介绍-CSDN博客

Qt绘图与图形视图之常见图形、路径、文字、图片的绘制介绍-CSDN博客

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

一、最终效果

左键点击画板,就可以移动鼠标开始绘制,双击左键结束绘制,或者右键点击也结束绘制。

二、具体实现

1、简单思路

主要两个类实现,一个负责绘制的逻辑实现,一个负责实现菜单,用了ui设计。

 2、菜单实现

我们要实现一个菜单,当用户单击鼠标右键时,会弹出一个菜单,让用户进行选择。

2.1、为什么在构造函数里创建菜单

在创建菜单的过程中,我们并没有把创建菜单封装成一个类,而是放在了构造函数里。为什么不把菜单栏创建过程放在contextMenuEvent方法里?而要放在构造函数里。

因为如果放在contextMenuEvent方法里,这意味着用户每单击鼠标一次,都会调用这个方法去创建一次菜单栏,而放在构造函数里就只用创建一次

2.2、假动作设计
 QAction* pAc3 = new QAction(QString::fromLocal8Bit("退出菜单"), this);

这是个假动作,为了让菜单消失,且不影响绘制路径

2.3、fromLocal8Bit()方法

fromLocal8Bit()将本地编码转换为QString,使用setShortcut方法为该QAction对象添加了快捷键"Ctrl+E" 

 //fromLocal8Bit()将本地编码转换为QStringQAction* pAc1 = new QAction(QString::fromLocal8Bit("结束绘制"), this);//使用setShortcut方法为该QAction对象添加了快捷键"Ctrl+E"pAc1->setShortcut(QKeySequence("Ctrl+E")); //添加快捷键
2.4、完整代码

 注释很详细,可以慢慢看。

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);//setFocusPolicy(Qt::StrongFocus);//setFocus();//下面是菜单栏创建过程,整体是很简单的,就不过多赘述//有一个问题,为什么不把菜单栏创建过程放在contextMenuEvent方法里//因为这意味着用户每单击鼠标一次,都会调用这个方法去创建一次菜单栏,而放在构造函数里就只用创建一次m_pMenu = new QMenu(this);//fromLocal8Bit()将本地编码转换为QStringQAction* pAc1 = new QAction(QString::fromLocal8Bit("结束绘制"), this);//使用setShortcut方法为该QAction对象添加了快捷键"Ctrl+E"pAc1->setShortcut(QKeySequence("Ctrl+E")); //添加快捷键QAction* pAc2 = new QAction(QString::fromLocal8Bit("清除"), this);pAc2->setShortcut(QKeySequence("Ctrl+D"));// 这是个假动作,为了让菜单消失,且不影响绘制路径QAction* pAc3 = new QAction(QString::fromLocal8Bit("退出菜单"), this);m_pMenu->addAction(pAc1);m_pMenu->addAction(pAc2);m_pMenu->addAction(pAc3);m_pMenu->setStyleSheet("QMenu{font:18px;}");connect(pAc1, &QAction::triggered, [=] {ui->graphicsPainter->endDraw();});connect(pAc2, &QAction::triggered, [=] {ui->graphicsPainter->clearPath();});
}MainWindow::~MainWindow()
{delete ui;
}// 右键菜单
void MainWindow::contextMenuEvent(QContextMenuEvent* event)
{//获取鼠标当前位置,并把菜单栏move到该位置m_pMenu->move(cursor().pos());//然后进行显示m_pMenu->show();//如果没有这一步,那么单击鼠标右键,菜单栏会在桌面左上角(0,0)位置处显示
}

3、绘图功能实现 

 3.1、主要的五个类
    void paintEvent(QPaintEvent *) override;void mousePressEvent(QMouseEvent *e) override;       //按下void mouseMoveEvent(QMouseEvent *e) override;        //移动void mouseReleaseEvent(QMouseEvent *e) override;     //松开void mouseDoubleClickEvent(QMouseEvent *event) override;     //双击
3.2、鼠标跟踪函数

首先是构造函数里的鼠标跟踪函数,这个是必须要有的 

MyPainterWidget::MyPainterWidget(QWidget *parent) : QWidget(parent)
{// 设置鼠标跟踪,以便在鼠标移动时能够及时更新绘图setMouseTracking(true);//清空点列表pointList.clear();
}
3.3、鼠标按下前清空画板

每次鼠标按下绘画之前,都会先清空画板 

// 按下
void MyPainterWidget::mousePressEvent(QMouseEvent *e)
{if (e->button() == Qt::LeftButton){if(!m_bStartDraw){//每次按下后开始绘画之前,也就是m_bStartDraw设置为真之前//都应该先清空整个画板pointList.clear();m_bStartDraw = true;}}   
}
3.4、重写绘图事件

 其次是重写绘图事件,这里创建了一个vector容器来存储线段,用for循环实现相邻点之间的线段连接,最后再绘制所有线段,注意,是先把需要绘制的线段都放在vector容器里,最后一起绘制的

void MyPainterWidget::paintEvent(QPaintEvent *)
{//在窗口上绘制内容QPainter painter(this);painter.setPen(QColor(255,0,0)); // 设置画笔颜色为红色QVector<QLineF> lines; // 存储线段的容器for(int i = 0; i < pointList.size()-1; i++){//在点列表pointList中的相邻点之间创建线段QLineF line(QPointF(pointList[i].x(), pointList[i].y()), QPointF(pointList[i+1].x(), pointList[i+1].y()));lines.push_back(line); // 将线段添加到容器中}如果正在绘制状态,则绘制鼠标移动到的点与最后一个点之间的线段if (m_bStartDraw){int size = pointList.size();if (bMove && size > 0){QLineF line(QPointF(pointList[pointList.size() - 1].x(), pointList[pointList.size() - 1].y()),movePoint);lines.push_back(line); // 将线段添加到容器中}}painter.drawLines(lines); // 绘制所有线段
}

可能会有个疑惑?最后才绘制所有线段,为什么实际操作的过程中感觉是一条一条绘制的

因为每次鼠标按下和松开的时候,都是进行了update()的,也就是说在每次添加新线段到lines容器时,都会触发paintEvent的调用,从而实时更新界面。这样就会看到每次添加新线段时都会立即绘制出来,就有一种逐条绘制的感觉。

// 移动
void MyPainterWidget::mouseMoveEvent(QMouseEvent *e)
{if(m_bStartDraw){movePoint = e->pos(); // 更新移动点的位置this->update(); // 更新绘图// 先刷新再设为true, 防止第一点和(0,0)连在一块bMove = true;}
}
// 松开
void MyPainterWidget::mouseReleaseEvent(QMouseEvent *e)
{if (e->button() == Qt::LeftButton){// 鼠标松开后,将点添加到路径中,并更新绘图if (m_bStartDraw){// 鼠标松开后的点需要添加到路径中pointList.push_back(QPointF(e->x(), e->y()));bMove = false;this->update();}}
}

以上就是Qt里移动鼠标手动绘制任意多边形的简单介绍

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

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

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

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

相关文章

【深度学习】第一门课 神经网络和深度学习 Week 4 深层神经网络

&#x1f680;Write In Front&#x1f680; &#x1f4dd;个人主页&#xff1a;令夏二十三 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd; &#x1f4e3;系列专栏&#xff1a;深度学习 &#x1f4ac;总结&#xff1a;希望你看完之后&#xff0c;能对…

临期食品店会员配送商城小程序的作用是什么

临期商品以量大价格低/即时性吸引市场大量客户&#xff0c;很多地区都有门店&#xff0c;行业也不乏连锁/加盟品牌&#xff0c;食品受众广且区域拓展性强&#xff0c;商家可线上销售提升营收和解决线下难题。 商家运用【雨科】平台搭建临期食品店商城小程序&#xff0c;对生意…

PyTorch如何修改模型(魔改)

文章目录 PyTorch如何修改模型&#xff08;魔改&#xff09;1.修改模型层(模型框架⭐)1.1通过继承修改模型1.2通过组合修改模型(重点学&#x1f440;)1.3通过猴子补丁修改模型 2.添加外部输入3.添加额外输出参考 PyTorch如何修改模型&#xff08;魔改&#xff09; 对模型缝缝补…

【算法刷题 | 动态规划02】5.02(不同路径、不同路径||、整数拆分、不同的二叉搜索树)

文章目录 5.不同路径5.1题目5.2解法一&#xff1a;深度搜索5.2.1深度搜索思路5.2.2代码实现 5.3解法二&#xff1a;动规5.3.1动规思路5.3.2代码实现 6.不同路径||6.1题目6.2解法&#xff1a;动规6.2.1动规思路&#xff08;1&#xff09;dp数组以及下标含义&#xff08;2&#x…

基于Springboot的交流互动系统

基于SpringbootVue的交流互动系统的设计与实现 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringbootMybatis工具&#xff1a;IDEA、Maven、Navicat 系统展示 用户登录 首页 帖子信息 聚会信息 后台登录 后台管理首页 用户管理 帖子分类管理 帖子信息…

Python语言零基础入门——文件

目录 一、文件的基本概念 1.文件 2.绝对路径与相对路径 3.打开文件的模式 二、文件的读取 三、文件的追加 四、文件的写入 五、with语句 六、csv文件 1.csv文件的读取 2.csv文件的写入 七、练习题&#xff1a;实现日记本 一、文件的基本概念 1.文件 文件是以计算…

Mysql中索引的概念

索引相关概念 基础概念&#xff1a; 在MySQL中&#xff0c;索引是一种数据结构&#xff0c;用于加快数据库查询的速度和性能。索引可以帮助MySQL快速定位和访问表中的特定数据&#xff0c;就像书籍的索引一样&#xff0c;通过存储指向数据行的指针&#xff0c;可以快速…

ICode国际青少年编程竞赛- Python-1级训练场-路线规划

ICode国际青少年编程竞赛- Python-1级训练场-路线规划 1、 Dev.step(3) Dev.turnLeft() Dev.step(4)2、 Dev.step(3) Dev.turnLeft() Dev.step(3) Dev.step(-6)3、 Dev.step(-2) Dev.step(4) Dev.turnLeft() Dev.step(3)4、 Dev.step(2) Spaceship.step(2) Dev.step(3)5、…

Android手写自己的路由SDK

实现自己的路由框架 ​ 在较大型的Android app中常会用到组件化技术&#xff0c;针对不同的业务/基础功能对模块进行划分&#xff0c;从上到下为壳工程、业务模块、基础模块。其中业务模块依赖基础模块&#xff0c;壳工程依赖业务模块。同级的横向模块&#xff08;比如多个业务…

软件杯 深度学习的动物识别

文章目录 0 前言1 背景2 算法原理2.1 动物识别方法概况2.2 常用的网络模型2.2.1 B-CNN2.2.2 SSD 3 SSD动物目标检测流程4 实现效果5 部分相关代码5.1 数据预处理5.2 构建卷积神经网络5.3 tensorflow计算图可视化5.4 网络模型训练5.5 对猫狗图像进行2分类 6 最后 0 前言 &#…

MySQL-逻辑架构

1、MySQL服务器处理客户端请求 MySQL是典型的C/S架构&#xff0c;服务端程序使用 mysqld。实现效果&#xff1a;客户端进程像服务端发送&#xff08;SQL语句&#xff09;&#xff0c;服务器进程处理后再像客户端进程发送 处理结果。 2、connectors 指不同语言中与SQL的交互…

【C++】双指针算法:四数之和

1.题目 2.算法思路 这道题目十分困难&#xff0c;在leetcode上的通过率只有36%&#xff0c;大家要做好心理准备。 在做个题目前强烈建议大家先看看我的上一篇博客&#xff1a;有效三角形个数&#xff0c;看完之后再去leetcode上写一写三数之和&#xff0c;搞懂那两个题目之后…

JavaEE 初阶篇-深入了解 Junit 单元测试框架和 Java 中的反射机制(使用反射做一个简易版框架)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 Junit 单元测试框架概述 1.1 使用 Junit 框架进行测试业务代码 1.2 Junit 单元测试框架的常用注解&#xff08;Junit 4.xxx 版本&#xff09; 2.0 反射概述 2.1 获…

计算机毕业设计php自行车在线租赁管理系统-vue+mysql

本系统的开发使获取自行车在线租赁管理系统信息能够更加方便快捷&#xff0c;同时也使自行车在线租赁管理系统管理信息变的更加系统化、有序化。系统界面较友好&#xff0c;易于操作。 自行车在线租赁管理系统&#xff0c;主要的模块包括首页、个人中心、用户管理、会员管理、自…

软件系统安全设计(安全保证措施)

软件安全保证措施word 软件所有全套资料获取进主页或者本文末个人名片直接。

C++之set/map相关实现

看着上面的图片&#xff0c;你可能对set和map的多样变化产生疑惑&#xff0c;下面我们就来详细讲解他们的区别以及实现 一.set/map 首先&#xff0c;在这里我们要声明&#xff0c;如果你对二叉搜索树一点都不了解的话&#xff0c;建议你先去将搜索二叉树学会再来学习这里的内…

ArkTS开发原生鸿蒙HarmonyOS短视频应用

HarmonyOS实战课程“2024鸿蒙零基础快速实战-仿抖音App开发&#xff08;ArkTS版&#xff09;”已经于今日上线至慕课网&#xff08;https://coding.imooc.com/class/843.html&#xff09;&#xff0c;有致力于鸿蒙生态开发的同学们可以关注一下。 课程简介 本课程以原生鸿蒙Ha…

【Canvas与艺术】新制无底图安布雷拉暗黑系桌面(1920*1080)

【主要变化】 1.去掉底图&#xff0c;改为金丝正六边形组合而成的网格&#xff1b; 2.将安布雷拉标志调暗&#xff1b; 【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html;…

力扣HOT100 - 78. 子集

解题思路&#xff1a; class Solution {public List<List<Integer>> subsets(int[] nums) {List<List<Integer>> lists new ArrayList<>(); // 解集lists.add(new ArrayList<Integer>()); // 首先将空集加入解集中for(int i 0; i < n…

Mac 安装 JDK21 流程

一、下载JDK21 访问Oracle官方网站或选择OpenJDK作为替代品。Oracle JDK从11版本开始是商业的&#xff0c;可能需要支付费用。OpenJDK是一个免费开源选项。 Oracle JDK官方网站&#xff1a;Oracle JDK Downloads OpenJDK官方网站&#xff1a;OpenJDK Downloads 这里以JDK21为…