关于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百度就行)