QMouseMoveEvent 和 QKeyEvent 修饰符的意外行为

Unexpected behaviour with QMouseMoveEvent and QKeyEvent modifiers

我在我的代码中遇到意外行为。 我有一个包含 QGraphicsScene 的 QGraphicsView。现在我想检测用于缩放视图的鼠标滚轮和用于移动场景中项目的鼠标移动,后者仅在按下控制键时检测。现在我有两个问题:

  1. 即使鼠标没有移动,只有鼠标滚轮移动,MouseMoveEvent 也会被调用。

  2. 在按下和不按下控件的情况下移动都可以正常工作,但是当我在按下控件的同时停止移动并继续使用鼠标滚轮时,不仅会调用 mousemoveevent,而且 controllmodifier 仍然处于活动状态。有什么问题吗?

main.cpp

#include "ppi.h"
#include <QtGui/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    PPI w;
    w.show();
    return a.exec();
}

ppi.h

#ifndef PPI_H
#define PPI_H

#include <QtGui/QMainWindow>
#include <QGraphicsView>
#include <QDebug>
#include <QWheelEvent>

#include "ui_ppi.h"
#include "ppiView.h"
#include "ppiscene.h"

class PPI : public QMainWindow
{
    Q_OBJECT

public:
    PPI(QWidget *parent = 0, Qt::WFlags flags = 0);
    ~PPI();
    int i;

private:
    Ui::ppiClass ui;
    PPIScene* ppiScene;

protected slots:
    void onZoom(QWheelEvent *event);
    void onMouseMoved(QGraphicsSceneMouseEvent *event);
};

#endif // PPI_H

ppi.cpp

#include "ppi.h"


PPI::PPI(QWidget *parent, Qt::WFlags flags)
    : QMainWindow(parent, flags)
{
    ui.setupUi(this);

    ppiScene = new PPIScene(this);

    connect(ppiScene, SIGNAL(mouseMoved(QGraphicsSceneMouseEvent*)), this, SLOT(onMouseMoved(QGraphicsSceneMouseEvent*)));
    connect(ui.gVPPI, SIGNAL(zoom(QWheelEvent*)), this, SLOT(onZoom(QWheelEvent*)));

    ppiScene->setSceneRect(0,0,1024,1024);
    ui.gVPPI->setScene(ppiScene);
    ui.gVPPI->setMouseTracking(true);

    i = 0;
}

PPI::~PPI()
{

}



void PPI::onZoom(QWheelEvent *event)
{
        if(event->delta() > 0)
            ui.gVPPI->scale(1.01, 1.01);
        else
            ui.gVPPI->scale(1/1.01, 1/1.01);
}


void PPI::onMouseMoved(QGraphicsSceneMouseEvent *event)
{
    i++;
    qDebug() << "slot" << i << event->modifiers();
    if(event->modifiers() & Qt::ControlModifier)
    {
        qDebug() << "ctrl pressed";
    }
}

ppiview.h

#ifndef PPIVIEW_H
#define PPIVIEW_H

#include <QGraphicsView>
#include <QMouseEvent>

class PPIView : public QGraphicsView
{
    Q_OBJECT

public:
    PPIView(QWidget * parent = 0);
    ~PPIView();

private:
    void wheelEvent(QWheelEvent *event);

signals:
    void zoom(QWheelEvent *event);

};

#endif // PPIVIEW_H

ppiview.cpp

#include "ppiview.h"

PPIView::PPIView(QWidget * parent)
    : QGraphicsView(parent)
{

}

PPIView::~PPIView()
{

}

void PPIView::wheelEvent(QWheelEvent *event)
{
    emit zoom(event);
}

ppiscene.h

#ifndef PPISCENE_H
#define PPISCENE_H

#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QDebug>

class PPIScene : public QGraphicsScene
{
    Q_OBJECT

public:
    PPIScene(QObject *parent);
    ~PPIScene();
    int i;

private:
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event);

signals:
    void mouseMoved(QGraphicsSceneMouseEvent *event);

};

#endif // PPISCENE_H

ppiscene.cpp

#include "ppiscene.h"

PPIScene::PPIScene(QObject *parent)
    : QGraphicsScene(parent)
{
    i = 0;
}

PPIScene::~PPIScene()
{

}

void PPIScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    i++;
    qDebug() << "signal" << i << event->modifiers();
    emit mouseMoved(event);
}

真是奇怪。看起来 Qt::KeyboardModifiers 状态,即 QGraphicsSceneMouseEvent::modifiers returns,只有在物理移动鼠标时才会更新。更奇怪的是,在您的代码中 QGraphicsSceneMouseMove 类型的 QGraphicsSceneMouseEvents 即使鼠标根本没有移动,但只有滚轮被转动时也会发送。也许由于您的缩放而导致的相对移动算作移动,而不是更新修改器的移动。

我能够重现您的问题:除非物理移动鼠标,否则修饰符的状态不会改变。

幸运的是,有一个简单的解决方法。在

void PPI::onMouseMoved(QGraphicsSceneMouseEvent *event)
{
    i++;
    qDebug() << "slot" << i << event->modifiers();
    if(event->modifiers() & Qt::ControlModifier)
    {
        qDebug() << "ctrl pressed";
    }
}

替换:

if(event->modifiers() & Qt::ControlModifier)

与:

if(QApplication::queryKeyboardModifiers() & Qt::ControlModifier)

当您按下或释放控制键时,QApplication::queryKeyboardModifiers() 会立即更新。