前言
接上一篇的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叠加的跟踪框是天蓝色的,也就是播放器显示的内容,可以看见和我们鼠标绘制的完全重合,重写完成!