Qt如何使用mouseMoveEvent移动视图

时间:2019-09-17 22:01:04

标签: c++ qt

在使用QGraphicsScene和QGraphicsView时,我想实现以下目标:如果鼠标位于屏幕的边界之一,则视图随之移动(就像大多数RTS游戏中的情况一样)。但是,当处理mouseMoveEvent时,我只会得到堆栈溢出,这很可能是因为一旦鼠标位于某个位置,该事件将被无限次调用。

我的相机类具有指向视图的指针,并继承QGraphicsRectItem并添加到主类的场景中。 有什么方法可以防止此事件在某个时刻发生?还是对此有一个优雅的解决方案?我尝试的另一个问题是,当我希望mouseMoveEvent工作时,相机类必须抓住鼠标。

void Camera::mouseMoveEvent(QGraphicsSceneMouseEvent* e)
{

    int view_x = view->mapFromScene(e->pos()).x();
    int view_y = view->mapFromScene(e->pos()).y();

    int horizontalSliderPos = view->horizontalScrollBar()->sliderPosition();
    int verticalSliderPos = view->verticalScrollBar()->sliderPosition();

    if (view_x < 100) {

            view->horizontalScrollBar()->setSliderPosition(horizontalSliderPos - 5);
        }
    if (view_x > Constants::VIEWWIDTH - 100) {
            view->horizontalScrollBar()->setSliderPosition(view->horizontalScrollBar()->sliderPosition() + 5);
        }
    if (view_y < 100) {
            view->verticalScrollBar()->setSliderPosition(view->verticalScrollBar()->sliderPosition() - 5);
        }
    if (view_y > Constants::VIEWHEIGHT - 100) {
            view->verticalScrollBar()->setSliderPosition(view->verticalScrollBar()->sliderPosition() + 5);
        }


}

2 个答案:

答案 0 :(得分:0)

经过一些尝试和实验,我获得了一个解决方案,这可能是一个很好的起点。如前所述,您必须中断mouseMoveEvent的递归调用。我用一个简单的布尔变量中断了递归调用,但是即使QSignalBlocker也会阻止所有信号,但在这里还是有用的。

我尝试实现的另一个功能是,如果鼠标的空白处没有移动,则仍然有一个移动的窗口。我通过使用QTimer(每25毫秒触发一次)来完成此操作。

main.cpp

#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QMainWindow>
#include "MyScene.h"

int main(int argc, char* argv[]) {
    QApplication app(argc, argv);
    auto view = new QGraphicsView;
    auto model = new MyScene;
    view->setMouseTracking(true);
    view->setScene(model);
    model->setView(view);
    model->addRect(QRectF(20, 20, 20, 20));
    model->addRect(QRectF(300, 20, 20, 20));
    model->addRect(QRectF(0, 0, 500, 500), QPen(Qt::blue)); // Complete Scene
    view->show();
    view->setSceneRect(QRectF(120, 20, 20, 20));
    return app.exec();
}

MyScene.h

#pragma once

#include <QDebug>
#include <QGraphicsSceneEvent>
#include <QGraphicsView>
#include <QTimer>

class MyScene : public QGraphicsScene {
    Q_OBJECT
public:
    MyScene(QWidget* parent=nullptr) : QGraphicsScene(parent) {
    }
    void setView(QGraphicsView* view) {
        mView = view;
    }

protected:
    void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override {
        if (mTranslating) return;
        delete mRepeater; // Destroys connect
        mRepeater = new QTimer;
        if (!mView) return;
        mTranslating = true;
        int tx{ 0 };
        int ty{ 0 };
        const int margin = 20;
        int sx = mView->mapFromGlobal(event->screenPos()).x();
        int sy = mView->mapFromGlobal(event->screenPos()).y();
        if (sx < margin) {
            tx = -1;
        }
        else if (sx > mView->width() - margin) {
            tx = 1;
        }
        if (sy < margin) {
            ty = -1;
        }
        else if (sy > mView->height() - margin) {
            ty = 1;
        }
        if (tx != 0 || ty != 0) {
            auto rect = mView->sceneRect();
            rect.translate(QPointF{ (qreal)tx,(qreal)ty });
            mView->setSceneRect(rect);
            connect(mRepeater, &QTimer::timeout, [=]() { // Moves even if mouse is not moved
                auto rect = mView->sceneRect();
                rect.translate(QPointF{ (qreal)tx,(qreal)ty });
                mView->setSceneRect(rect);
            });
            mRepeater->start(25);
        }
        mTranslating = false;
    }

    QGraphicsView* mView{ nullptr };
    bool mTranslating{ false };
    QTimer* mRepeater{ nullptr };
};

答案 1 :(得分:0)

我认为,如果您在QGraphicsView类中处理鼠标移动事件而不是在QGraphicsScene类中处理鼠标移动事件,则可以避免。