接上一篇的rtsp播放器,有需要在播放界面手动跟踪,就需要在播放界面绘制矩形框,并把当前鼠标绘制区域的宽高坐标进行换算发送给3559,做进一步处理。绘制矩形框共分为两种,第一种是左键拖动绘制,第二种是直接在鼠标位置绘制固定的矩形框,用鼠标滚轮调动框的大小,再加上退出功能,需求就可以实现了。对于qt来说也比较简单,重写对应的事件即可
首先,我们需要一个基于Qt的图形界面应用程序,以便可以在其中添加功能。在程序中,我们可以使用Qt提供的QPainter类来画矩形框。可以使用QPainter的drawRect函数来绘制矩形框,并且可以使用鼠标事件来获取绘制矩形框的坐标。
#include
#include
#include
#include
#include
在绘制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();
};
为了做出区分,可以选择鼠标左键+键盘的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();
}
}
}
释放的时候只需要将获取到的坐标存储在矩形的末点位置,更新即可
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();
}
}
}
}
画框需要和绘制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);
#else
painter.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;
移动的时候更新坐标就行了,我们直接使用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();
}
我们先调用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();;
}
我们需要计算出鼠标位置相对于矩形框中心点的偏移量,并在打印时减去偏移量,以使鼠标位置在矩形框的正中心。
同时这次用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(); // 发送信号
}
}
}
绘制事件中设置颜色再次调用drawRect即可
painter.setPen(Qt::white);
painter.drawRect(m_rect);
这个时候的取消绘制直接把滚轮调小即可