QT:界面上重写鼠标事件(画框,鼠标更改)

前言

  接上一篇的rtsp播放器,有需要在播放界面手动跟踪,就需要在播放界面绘制矩形框,并把当前鼠标绘制区域的宽高坐标进行换算发送给3559,做进一步处理。绘制矩形框共分为两种,第一种是左键拖动绘制,第二种是直接在鼠标位置绘制固定的矩形框,用鼠标滚轮调动框的大小,再加上退出功能,需求就可以实现了。对于qt来说也比较简单,重写对应的事件即可

拖动绘制

  首先,我们需要一个基于Qt的图形界面应用程序,以便可以在其中添加功能。在程序中,我们可以使用Qt提供的QPainter类来画矩形框。可以使用QPainter的drawRect函数来绘制矩形框,并且可以使用鼠标事件来获取绘制矩形框的坐标。

包含头文件

#include <QtWidgets/QApplication>
#include <QtWidgets/QWidget>
#include <QMouseEvent>
#include <QPainter>
#include <QDebug>

声明重载

  在绘制h264的class中重写对应事件

virtual void mousePressEvent(QMouseEvent *event) override;
virtual void mouseReleaseEvent(QMouseEvent *event) override;
virtual void paintEvent(QPaintEvent *event) override;
QPoint m_rectStart;
QPoint m_rectEnd;
`

   class FFmpegWidget : public QWidget
{Q_OBJECT
public:explicit FFmpegWidget(QWidget *parent = 0);~FFmpegWidget();
//    FFmpegWidget(QWidget *parent = nullptr) : QWidget(parent)
//       {
//           setMouseTracking(true);
//       }virtual void mousePressEvent(QMouseEvent *event) override;virtual void mouseReleaseEvent(QMouseEvent *event) override;protected:   
//    virtual void paintEvent(QPaintEvent *) override;
//    virtual void mousePressEvent(QMouseEvent *event) override;
//    virtual void mouseReleaseEvent(QMouseEvent *event) override;virtual void paintEvent(QPaintEvent *event) override;void mouseMoveEvent(QMouseEvent *event) override;void wheelEvent(QWheelEvent *event) override;private:FFmpegThread *thread;QImage image;QPoint m_rectStart;QPoint m_rectEnd;QRect m_rect;private slots://接收图像并绘制void updateImage(const QImage &image);
signals:void buttonClicked_ctrl_left();//通知串口网口void buttonClicked_shift_left();//通知串口网口void buttonClicked_exit_left();//通知串口网口public slots://设置视频流地址void setUrl(const QString &url);//打开设备void open();//暂停void pause();//继续void next();//关闭设备void close();//清空void clear();
};

mousePressEvent

  为了做出区分,可以选择鼠标左键+键盘的ctrl键时生效绘制黑色矩形框(默认颜色),点击的时候获取坐标

void FFmpegWidget::mousePressEvent(QMouseEvent *event)
{
//     qDebug()<<"mousePressEvent";if (event->button() == Qt::LeftButton){if(QApplication::keyboardModifiers() == Qt::ControlModifier){
//            clear_rect = false;m_rectStart = event->pos();}}}

mouseReleaseEvent

  释放的时候只需要将获取到的坐标存储在矩形的末点位置,更新即可

void FFmpegWidget::mouseReleaseEvent(QMouseEvent *event){
//     qDebug()<<"mousereleaseEvent";if (event->button() == Qt::LeftButton){if(QApplication::keyboardModifiers() == Qt::ControlModifier){if(QApplication::keyboardModifiers() == Qt::ControlModifier){m_rectEnd = event->pos();update();}}}}

paintEvent

  画框需要和绘制h264视频在同一个事件,在后面添加坐标调用drawRect即可

QRectF rect = QRectF(m_rectStart, m_rectEnd);
painter.drawRect(rect);

void FFmpegWidget::paintEvent(QPaintEvent *)
{/*显示h264*/if (image.isNull()) {return;}//qDebug() << TIMEMS << "paintEvent" << objectName();QPainter painter(this);
#if 0//image = image.scaled(this->size(), Qt::KeepAspectRatio);//按照比例自动居中绘制int pixX = rect().center().x() - image.width() / 2;int pixY = rect().center().y() - image.height() / 2;QPoint point(pixX, pixY);painter.drawImage(point, image);
#elsepainter.drawImage(this->rect(), image);/*计算坐标*/g_window_w = (rect().center().x())*2;g_window_h =(rect().center().y())*2;g_video_w = image.width();g_video_h = image.height();/*ctrl加鼠标左键开始画框*/QRectF rect = QRectF(m_rectStart, m_rectEnd);painter.drawRect(rect);#endif
}

取消绘制

  画好的黑框总不能一直显示,看见和目标重合后根据需要取消即可,常用鼠标右键取消,我们再次添加事件mousePressEvent,同时新增bool clear_rect 用于提醒绘制的时候取消绘制即可,在mouseReleaseEvent中在置为false即可在下次绘制时重新使能

if (event->button() == Qt::RightButton){clear_rect = true;}

  paintEvent中将drawRect添加至判断内,对于坐标的计算也放置在这里

 if(!clear_rect){painter.drawRect(rect);//        qDebug() << "Rect1: " << rect.x() << ", " << rect.y() << ", " << rect.width() << ", " << rect.height()<<", " << rect.center().x()<<", " << rect.center().y();g_mouse_w = (int)((rect.width()*g_video_w)/g_window_w);g_mouse_h = (int)((rect.height()*g_video_h)/g_window_h);g_mouse_x = (int)(((rect.x()*g_video_w)/g_window_w) + 0.5f*(g_mouse_w-1));g_mouse_y = (int)(((rect.y()*g_video_h)/g_window_h) + 0.5f*(g_mouse_h-1));}

点击绘制

  有区别的是需要在鼠标移动的时候更新框的位置,并且需要重写鼠标滚轮的事件用来调整框的大小。这次的位置信息只需要一个就够了,可以直接使用QRect::setSize函数来设置矩形框的大小

void mouseMoveEvent(QMouseEvent *event) override;
void wheelEvent(QWheelEvent *event) override;
QRect m_rect;

mouseMoveEvent

  移动的时候更新坐标就行了,我们直接使用QRect::moveCenter函数来移动矩形框。

void FFmpegWidget::mouseMoveEvent(QMouseEvent *event)
{
//      qDebug() << "mouseMoveEvent " ;QPoint center = m_rect.center();int dx = event->pos().x() - center.x();int dy = event->pos().y() - center.y();m_rect.moveCenter(event->pos());update();
}

wheelEvent

  我们先调用QCursor::pos函数获取当前鼠标位置,然后使用QWidget::mapFromGlobal函数将其转换为窗口内的坐标,最后使用QRect::moveCenter函数来移动矩形框。

void FFmpegWidget::wheelEvent(QWheelEvent *event)
{
//      qDebug() << "wheelEvent " ;int delta = event->angleDelta().y();QSize size = m_rect.size();size += QSize(delta / 120, delta / 120);m_rect.setSize(size);m_rect.moveCenter(mapFromGlobal(QCursor::pos()));update();;
}

mousePressEvent

  我们需要计算出鼠标位置相对于矩形框中心点的偏移量,并在打印时减去偏移量,以使鼠标位置在矩形框的正中心。
同时这次用shift+鼠标左键和之前直接拖动绘制的区分开

 void FFmpegWidget::mousePressEvent(QMouseEvent *event)
{if (event->button() == Qt::LeftButton){if(QApplication::keyboardModifiers() == Qt::ShiftModifier){g_rect_w = (int)((m_rect.width())*g_video_w/g_window_w);g_rect_h = (int)((m_rect.height())*g_video_h/g_window_h);g_rect_x = (int)((event->pos().x())*g_video_w/g_window_w);g_rect_y = (int)((event->pos().y())*g_video_h/g_window_h);emit buttonClicked_shift_left(); // 发送信号}}}

paintEvent

  绘制事件中设置颜色再次调用drawRect即可

painter.setPen(Qt::white);
painter.drawRect(m_rect);

取消绘制

  这个时候的取消绘制直接把滚轮调小即可

测试

在这里插入图片描述
在这里插入图片描述
  3559叠加的跟踪框是天蓝色的,也就是播放器显示的内容,可以看见和我们鼠标绘制的完全重合,重写完成!

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

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

相关文章

Z函数的原理和应用:以Python为例

Z函数 也就是&#xff0c;它想找前缀和以s[i]开头的后缀的LCP 思想 维护一个右端点最右的z-box 结合z[i - l]的结果和朴素算法进行优化 Z函数Python模版 def sumScores(self, s: str) -> int:n len(s)z [0] * nl r 0 # 右端点最右的z-boxfor i in range(1, n):if i &…

Etsy做什么店铺比较靠谱? 什么叫做真人店?

作为Etsy是美国最大的原创手工在线销售平台之一&#xff0c;以其店铺利润高、平台佣金低、平台同质化不严重的优点在跨境电商里颇具竞争力。然而Etsy开店却不是件容易事&#xff0c;原因是Etsy真人店对于环境以及卖家的运营操作要求较高&#xff0c;下面就给各位有意入局Etsy的…

Linux Shell编程系列--变量的定义与使用

一、目的 上一篇我们简单介绍了shell脚本的组成以及如何运行一个shell脚本&#xff0c;本篇将详解讲解shell中的变量。在Shell脚本中&#xff0c;变量是用来存储和处理数据的基本结构。 二、介绍 1、定义变量 变量名与等号&#xff08;&#xff09;后跟值来定义一个变量&#…

Java入门之JavaSe(韩顺平p1-p?)

学习背景&#xff1a; 本科搞过一段ACM、研究生搞了一篇B会后&#xff0c;本人在研二要学Java找工作啦~~&#xff08;宇宙尽头是Java&#xff1f;&#xff09;爪洼纯小白入门&#xff0c;C只会STL、python只会基础Pytorch、golang参与了一个Web后端项目&#xff0c;可以说项目小…

陪诊系统|陪诊小程序|陪诊服务让就医更容易

陪诊系统已经出现了好几年。尤其是这两年&#xff0c;它得到了人们的广泛认可。陪诊行业的快速发展主要是因为人们对这个行业的需求非常大。目前&#xff0c;我国面临着严重的老龄化问题&#xff0c;生活节奏也越来越快&#xff0c;有时候无法亲自陪伴在老人的身边。陪诊工作人…

【详解】斗地主随机发牌项目

目录 前言&#xff1a; 1.初始化牌 2.洗牌 3.揭牌 总代码&#xff1a; Card类&#xff1a; CardGame类&#xff1a; Main类&#xff1a; 结语&#xff1a; 前言&#xff1a; 斗地主是全国范围内的一种桌面游戏&#xff0c;本节我们来实现一下斗地主中的简单初始化牌、…

mfc110.dll是什么?解决mfc110.dll丢失windows系统常见问题

今天我在打开电脑软件时候&#xff0c;突然报错出现找不到mfc110.dll丢失&#xff0c;无法打开软件&#xff0c;我不知道是什么原因&#xff0c;后面找了很久才找到解决方法&#xff0c;那么mfc110.dll是什么&#xff1f;为什么会丢失和mfc110.dll解决方法是什么&#xff0c;今…

基础面试题整理6之Redis

1.Redis的应用场景 Redis支持类型&#xff1a;String、hash、set、zset、list String类型 hash类型 set类型 zset类型 list类型 一般用作缓存&#xff0c;例如 如何同时操作同一功能 2.redis是单线程 Redis服务端(数据操作)是单线程&#xff0c;所以Redis是并发安全的,因…

LeetCode-第876题-链表的中间结点

1.题目描述 给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。如果有两个中间结点&#xff0c;则返回第二个中间结点。 2.样例描述 3.思路描述 创建两个快慢指针 slow , fast &#xff0c;起始共同指向头节点&#xff0c;slow 每次走一步&#xff0c;fas…

子集枚举介绍

集合枚举的意思是从一个集合中找出它的所有子集。集合中每个元素都可以被选或不选&#xff0c;含有n个元素的集合总共有个子集&#xff08;包括全集和空集&#xff09; 例如考虑集合和它的4个子集、、、&#xff0c;按照某个顺序&#xff0c;把全集A中的每个元素在每个子集中的…

【数据开发】pyspark入门与RDD编程

【数据开发】pyspark入门与RDD编程 文章目录 1、pyspark介绍2、RDD与基础概念3、RDD编程3.1 Transformation/Action3.2 数据开发流程与环节 1、pyspark介绍 pyspark的用途 机器学习专有的数据分析。数据科学使用Python和支持性库的大数据。 spark与pyspark的关系 spark是一…

Mac OS中创建适合网络备份的加密镜像文件:详细步骤与参数选择

这篇文章提供了在Mac OS中创建适合网络备份的加密镜像文件的详细步骤&#xff0c;同时探讨了在选择相关参数时的关键考虑因素&#xff0c;以确保用户能够安全、高效地存储和保护重要数据。 创建步骤 在Mac OS Monterey中&#xff0c;你可以使用“磁盘工具”&#xff08;Disk …