关于QGraphicsView中重载的mouseMoveEvent失效的解决办法--通过事件过滤器来捕获鼠标事件,然后通过信号发送出去

关于QGraphicsView中重载的mouseMoveEvent失效的解决办法

QT版本:Qt_5.15.2

编译环境:MinGW 8.1.0 32 bit for C++

需要用QT写一个跨平台的软件,我使用的是Design直接拖拽的QGraphicsView,需要捕获鼠标在QGraphicsView范围内的移动事件。

在网上查了资料,结果基本都是重写mouseMoveEvent,但是我写了后,发现无法进入到对应的槽函数中。又在网上找资料,发现QGraphicsView父类中MouseMove和MouseButtonRelease事件获取办法_qgraphicsview qmouse_一剑破长空的博客-CSDN博客   写得很好,总之一句话就是“鼠标事件被QGraphicsView里面的viewport截取了,需要通过在viewport上安装一个事件过滤器,通过事件过滤来截取鼠标事件,实现鼠标事件的透传”。

因此,为了方便自己后面使用,因此将事件过滤器单独写了一个类,在捕获到鼠标事件后,通过信号发送出去。

#ifndef MOUSEFILTER_H
#define MOUSEFILTER_H


#include <QObject>
#include <QMouseEvent>




//自定义的鼠标变量
struct SongMousePoint {
    int x;//鼠标实时位置-X
    int y;//鼠标实时位置-Y
    int iXJustDown;//鼠标刚按下时的位置-X
    int iYJustDown;//鼠标刚按下时的位置-Y
    float fAngle;//鼠标滚轮转动的角度(度)-正前负后
};




class QGraphicsView;


class MouseFilter : public QObject
{
    Q_OBJECT
public:
    explicit MouseFilter(QGraphicsView *view, QObject *parent = nullptr);


signals:
    //移动
    void MouseMove(SongMousePoint);//鼠标移动


    //按下
    void LeftButtonDown(SongMousePoint);//鼠标左键按下
    void MiddleButtonDown(SongMousePoint);//鼠标中键按下
    void RightButtonDown(SongMousePoint);//鼠标右键按下


    //拖动--鼠标按下并移动
    void MouseMoveWithLeftButtonDown(SongMousePoint);//鼠标左键拖动
    void MouseMoveWithMiddleButtonDown(SongMousePoint);//鼠标中键拖动
    void MouseMoveWithRightButtonDown(SongMousePoint);//鼠标右键拖动


    //点击--表示从鼠标按下到抬起,鼠标位置没变
    void LeftButtonClick(SongMousePoint);//鼠标左键点击
    void MiddleButtonClick(SongMousePoint);//鼠标中键点击
    void RightButtonClick(SongMousePoint);//鼠标右键点击


    //抬起--表示鼠标从按下到抬起,鼠标位置发生变化
    void LeftButtonUp(SongMousePoint);//鼠标左键抬起
    void MiddleButtonUp(SongMousePoint);//鼠标中键抬起
    void RightButtonUp(SongMousePoint);//鼠标右键抬起


    //双击--鼠标当前点击和上一次点击不超过一定的时间
    void LeftButtonDoubleClick(SongMousePoint);//鼠标左键点击
    void MiddleButtonDoubleClick(SongMousePoint);//鼠标中键点击
    void RightButtonDoubleClick(SongMousePoint);//鼠标右键点击


    //滚轮
    void WheelScroll(SongMousePoint);


protected:
    bool eventFilter(QObject *watched, QEvent *event) override;


private:
    bool bFree;
    QGraphicsView *m_view;
    SongMousePoint m_MousePoint;


    //timer
    QTimer m_TimerLeftBtnDblClick;
    QTimer m_TimerRightBtnDblClick;
    QTimer m_TimerMiddleBtnDblClick;
public:
    bool m_bNeedDoubleClick;//是否需要双击(默认需要双击)
private slots:
    void onTimerTimeout_LeftButtomDoubleClick();//定时超出,则发送单击信号出去(双击会在timer未结束前,停止timer)
    void onTimerTimeout_MiddleButtomDoubleClick();//定时超出,则发送单击信号出去(双击会在timer未结束前,停止timer)
    void onTimerTimeout_RightButtomDoubleClick();//定时超出,则发送单击信号出去(双击会在timer未结束前,停止timer)
};


#endif // MOUSEFILTER_H
#include "mouseeventfilter.h"
#include <QDebug>
#include <QGraphicsView>


MouseFilter::MouseFilter(QGraphicsView *view, QObject *parent)
    : QObject(parent),
      m_view(view)
{
    view->viewport()->setMouseTracking(true);
    view->viewport()->installEventFilter(this);
    bFree=true;
    m_bNeedDoubleClick=false;


    //设置双击定时器
    m_TimerLeftBtnDblClick.setInterval(QApplication::doubleClickInterval());
    m_TimerLeftBtnDblClick.setSingleShot(true);
    connect(&m_TimerLeftBtnDblClick,&QTimer::timeout,this,&MouseFilter::onTimerTimeout_LeftButtomDoubleClick);


    m_TimerMiddleBtnDblClick.setInterval(QApplication::doubleClickInterval());
    m_TimerMiddleBtnDblClick.setSingleShot(true);
    connect(&m_TimerMiddleBtnDblClick,&QTimer::timeout,this,&MouseFilter::onTimerTimeout_MiddleButtomDoubleClick);


    m_TimerRightBtnDblClick.setInterval(QApplication::doubleClickInterval());
    m_TimerRightBtnDblClick.setSingleShot(true);
    connect(&m_TimerRightBtnDblClick,&QTimer::timeout,this,&MouseFilter::onTimerTimeout_RightButtomDoubleClick);


}


bool MouseFilter::eventFilter(QObject *watched, QEvent *event)
{
    QMouseEvent *mouseEvent1 = static_cast<QMouseEvent*>(event);
    QPointF pos1(mouseEvent1->pos());//将坐标转换成相对于左上角的坐标
    if(watched==m_view->viewport()&&mouseEvent1)//判断是否为QGraphicsView的视口事件及判断是否为鼠标事件
    {
        //记录当前实时鼠标位置
        m_MousePoint.x=pos1.x();
        m_MousePoint.y=pos1.y();
        switch(event->type())
        {
        case QEvent::MouseButtonPress://鼠标按下事件
            //记录下鼠标按下时的位置
            m_MousePoint.iXJustDown=pos1.x();
            m_MousePoint.iYJustDown=pos1.y();
            switch (mouseEvent1->button())
            {
            case Qt::LeftButton://左键
                emit LeftButtonDown(m_MousePoint);
                break;
            case Qt::MiddleButton://中键
                emit MiddleButtonDown(m_MousePoint);
                break;
            case Qt::RightButton://右键
                emit RightButtonDown(m_MousePoint);
                break;
            default:
                break;
            }
            break;
        case QEvent::MouseButtonRelease://鼠标释放事件
            //根据鼠标是否移动来判断是点击(还要区分是单击,还是双击),还是拖动
            if(m_MousePoint.x==m_MousePoint.iXJustDown&&m_MousePoint.y==m_MousePoint.iYJustDown)//鼠标未移动-点击
            {
                switch (mouseEvent1->button())
                {
                case Qt::LeftButton://左键
                    if(m_bNeedDoubleClick)//需要双击
                    {
                        if(m_TimerLeftBtnDblClick.isActive())//timer正在运行,表明距离上一次点击的时间间隔短,表明是双击
                        {
                            m_TimerLeftBtnDblClick.stop();//停止timer
                            emit LeftButtonDoubleClick(m_MousePoint);
                        }
                        else//timer已经停止,表明时间已经超过了
                        {
                            m_TimerLeftBtnDblClick.start();//启动timer
                            //emit LeftButtonClick(m_MousePoint);
                        }
                    }
                    else //不需要双击,直接发送单击信号
                    {
                        emit LeftButtonClick(m_MousePoint);
                    }


                    break;
                case Qt::MiddleButton://中键
                    if(m_bNeedDoubleClick)//需要双击
                    {
                        if(m_TimerMiddleBtnDblClick.isActive())//timer正在运行,表明距离上一次点击的时间间隔短,表明是双击
                        {


                            m_TimerMiddleBtnDblClick.stop();//停止timer
                            emit MiddleButtonDoubleClick(m_MousePoint);
                        }
                        else//timer已经停止,表明时间已经超过了
                        {
                            m_TimerMiddleBtnDblClick.start();//启动timer
                            //emit MiddleButtonClick(m_MousePoint);
                        }
                    }
                    else //不需要双击,直接发送单击信号
                    {
                        emit MiddleButtonClick(m_MousePoint);
                    }
                    break;
                case Qt::RightButton://右键
                    if(m_bNeedDoubleClick)//需要双击
                    {
                        if(m_TimerRightBtnDblClick.isActive())//timer正在运行,表明距离上一次点击的时间间隔短,表明是双击
                        {
                            m_TimerRightBtnDblClick.stop();//停止timer
                            emit RightButtonDoubleClick(m_MousePoint);
                        }
                        else//timer已经停止,表明时间已经超过了
                        {
                            m_TimerRightBtnDblClick.start();//启动timer
                            //emit RightButtonClick(m_MousePoint);
                        }
                    }
                    else //不需要双击,直接发送单击信号
                    {
                        emit RightButtonClick(m_MousePoint);
                    }
                    break;
                default:
                    break;
                }
            }
            else//鼠标移动了-鼠标release事件(buttomUP)
            {
                switch (mouseEvent1->button())
                {
                case Qt::LeftButton://左键
                    emit LeftButtonUp(m_MousePoint);
                    break;
                case Qt::MiddleButton://中键
                    emit MiddleButtonUp(m_MousePoint);
                    break;
                case Qt::RightButton://右键
                    emit RightButtonUp(m_MousePoint);
                    break;
                default:
                    break;
                }
            }


            break;


        case QEvent::MouseMove:
            //根据鼠标是否有按键按下,来判断是否为移动或拖动
            switch (mouseEvent1->buttons())//判断事件发生时,鼠标按钮的按下情况
            {
            case Qt::LeftButton://左键已经按下
                emit MouseMoveWithLeftButtonDown(m_MousePoint);
                break;
            case Qt::MiddleButton://中键已经按下
                emit MouseMoveWithMiddleButtonDown(m_MousePoint);
                break;
            case Qt::RightButton://右键已经按下
                emit MouseMoveWithRightButtonDown(m_MousePoint);
                break;
            case Qt::NoButton://无按键
                emit MouseMove(m_MousePoint);
            default:
                break;
            }
            break;
        case QEvent::Wheel:
        {
            QWheelEvent *wheelEvent = static_cast<QWheelEvent*>(event);
            m_MousePoint.fAngle = wheelEvent->angleDelta().y()/8.0;
            emit WheelScroll(m_MousePoint);
            break;
        }
        default:
            break;
        }
    }
    return false;
}


//定时超出,则发送单击信号出去(双击会在timer未结束前,停止timer)
void MouseFilter::onTimerTimeout_LeftButtomDoubleClick()
{
    emit LeftButtonClick(m_MousePoint);
}


//定时超出,则发送单击信号出去(双击会在timer未结束前,停止timer)
void MouseFilter::onTimerTimeout_MiddleButtomDoubleClick()
{
    emit MiddleButtonClick(m_MousePoint);
}


//定时超出,则发送单击信号出去(双击会在timer未结束前,停止timer)
void MouseFilter::onTimerTimeout_RightButtomDoubleClick()
{
    emit RightButtonClick(m_MousePoint);
}

在需要接收信号的类(一般是对话框或者widget)中,创建一个MouseFilter对象的成员变量

MouseFilter* m_MF_Start;

然后再构造函数中new一下,new了之后,设置一下是否需要双击

m_MF_Start=new MouseFilter(ui->graphicsView_Start,this);
m_MF_Start->m_bNeedDoubleClick=false;

然后在connect一下就行(槽函数及connect百度就行)​

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值