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

前言

  接上一篇的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();
};

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);
#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;

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);

取消绘制

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

测试

QT:界面上重写鼠标事件(画框,鼠标更改)_第1张图片
QT:界面上重写鼠标事件(画框,鼠标更改)_第2张图片
  3559叠加的跟踪框是天蓝色的,也就是播放器显示的内容,可以看见和我们鼠标绘制的完全重合,重写完成!

你可能感兴趣的:(QT,qt,计算机外设,开发语言)