QWheelEvent not working when using N.2 QGraphicsVi

2019-05-30 04:59发布

问题:

I am building a user interface that has N.2 QGraphicsView and I am only able to zoom in-out on one QGraphicsView. I am using QWheelEvent + CTRL for one QGraphicsView and QWheelEvent + ALT for the second QGraphicsView.

I read very useful articles to develop this procedure such as this and this but all of them are for zooming in-out for only one QGraphicsView. So sorry for writing with this problem again but I have been struggling a lot in the past days since I am trying to do it for two different QGraphicsView..

I am including a snippet of the code (mostly I used code from this post ) to do the zooming. Please let me know what I am doing wrong.

mainwindow.h

private:
    Qt::KeyboardModifiers _modifiers;
    double _zoom_factor_base;
    QPointF target_scene_pos, target_viewport_pos;
    bool eventFilter(QObject* object, QEvent* event);

    Qt::KeyboardModifiers _modifiersRight;
    double _zoom_factor_base_right;
    QPointF target_scene_pos_right, target_viewport_pos_right;
    bool altDown = false;

signals:
    void zoomed();
    void zoomedRight();

protected:
    void keyPressEvent(QKeyEvent *event);
    void keyReleaseEvent(QKeyEvent *event);

mainwindow.cpp

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{    
     ui->setupUi(this);
     ui->leftView->viewport()->installEventFilter(this);
     ui->leftView->setMouseTracking(true);
     _modifiers = Qt::ControlModifier;
     _zoom_factor_base = 1.0015;
     ui->rightView->viewport()->installEventFilter(this);
     ui->rightView->setMouseTracking(true);
     _modifiersRight = Qt::ControlModifier;
     _zoom_factor_base_right = 1.0015;
}

void MainWindow::gentle_zoom(double factor)
{
     ui->leftView->scale(factor, factor);
     ui->leftView->centerOn(target_scene_pos);
     QPointF delta_viewport_pos = target_viewport_pos - QPointF(ui->leftView->viewport()->width() / 2.0,

     ui->leftView->viewport()->height() / 2.0);
     QPointF viewport_center =
     ui->leftView->mapFromScene(target_scene_pos) - delta_viewport_pos;
     ui->leftView->centerOn(ui->leftView >mapToScene(viewport_center.toPoint()));
     emit zoomed();
}
void MainWindow::set_modifiers(Qt::KeyboardModifiers modifiers)
{
     _modifiers = modifiers;
}

void MainWindow::set_zoom_factor_base(double value)
{
     _zoom_factor_base = value;
}

void MainWindow::gentle_zoom_right(double factor)
{
     ui->rightView->scale(factor, factor);
     ui->rightView->centerOn(target_scene_pos_right);
     QPointF delta_viewport_pos = target_viewport_pos_right -
     QPointF(ui->rightView->viewport()->width() / 2.0,

     ui->rightView->viewport()->height() / 2.0);
     QPointF viewport_center = ui->rightView->mapFromScene(target_scene_pos_right) - delta_viewport_pos;
     ui->rightView->centerOn(ui->rightView >mapToScene(viewport_center.toPoint())); 
     emit zoomedRight();
 }

void MainWindow::set_modifiers_right(Qt::KeyboardModifiers modifiers)
{
     _modifiersRight = modifiers;
}

void MainWindow::set_zoom_factor_base_right(double value)
{
     _zoom_factor_base_right = value;
}

bool MainWindow::eventFilter(QObject *object, QEvent *event)
{
     if (event->type() == QEvent::MouseMove)
         {
              QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
              QPointF delta = target_viewport_pos - mouse_event->pos();
              if (qAbs(delta.x()) > 5 || qAbs(delta.y()) > 5)
              {
                  target_viewport_pos = mouse_event->pos();
                  target_scene_pos = ui->leftView->mapToScene(mouse_event->pos());
               }
         }
         else if (event->type() == QEvent::Wheel)
         {
              QWheelEvent* wheel_event = static_cast<QWheelEvent*>(event);
              if (QApplication::keyboardModifiers() == _modifiers)
              {
                  if (wheel_event->orientation() == Qt::Vertical)
                  {
                      double angle = wheel_event->angleDelta().y();
                      double factor = qPow(_zoom_factor_base_right, angle);
                      gentle_zoom(factor);
                      return true;
                  }
              }
         }
         if(altDown) // I repeat the same procedure but for the rightView
         {
              if (event->type() == QEvent::MouseMove)
              {
                   QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
                   QPointF delta = target_viewport_pos_right - mouse_event->pos();
                   if (qAbs(delta.x()) > 5 || qAbs(delta.y()) > 5)
                   {
                        target_viewport_pos_right = mouse_event->pos();
                        target_scene_pos_right = ui->rightView->mapToScene(mouse_event->pos());
                    }
                }
                else if (event->type() == QEvent::Wheel)
                {
                    QWheelEvent* wheel_event = static_cast<QWheelEvent*>(event);
                    if (QApplication::keyboardModifiers() == _modifiersRight)
                    {
                         if (wheel_event->orientation() == Qt::Vertical)
                         {
                             double angle = wheel_event->angleDelta().y();
                             double factor = qPow(_zoom_factor_base_right, angle);
                             gentle_zoom_right(factor);
                             return true;
                         }
                    }
                }
          }
          Q_UNUSED(object)
          return false;
}

void MainWindow::keyReleaseEvent(QKeyEvent *event)
{
     if(event->key() == Qt::Key_Alt) { altDown = false; }
}

void MainWindow::keyPressEvent(QKeyEvent *event)
{
     if(event->key() == Qt::Key_Alt) { altDown = true; }
}

回答1:

You must learn about the Single responsibility principle, where it indicates that each class has its own responsibility, and in this case it would avoid having a lot of messiness. The responsibility of the zoom is of the QGraphicsView, it is not the one of the MainWindow.

To do this, a new class is created that inherits from QGraphicsView and we implement the zoom functionality:

graphicsview.h

#ifndef GRAPHICSVIEW_H
#define GRAPHICSVIEW_H

#include <QGraphicsView>

class GraphicsView : public QGraphicsView
{
public:
    GraphicsView(QWidget *parent=nullptr);
    void setModifiers(const Qt::KeyboardModifiers &modifiers);
protected:
    void wheelEvent(QWheelEvent *event) override;
private:
    void applyZoom(double factor, const QPoint &fixedViewPos);
    Qt::KeyboardModifiers m_modifiers;
    const double base = 1.0015;
};

#endif // GRAPHICSVIEW_H

graphicsview.cpp

#include "graphicsview.h"

#include <QWheelEvent>
#include <QtMath>

GraphicsView::GraphicsView(QWidget *parent):
    QGraphicsView(parent)
{}

void GraphicsView::setModifiers(const Qt::KeyboardModifiers &modifiers)
{
    m_modifiers = modifiers;
}

void GraphicsView::wheelEvent(QWheelEvent *event)
{
    if(event->modifiers() == m_modifiers){
        double angle = event->orientation() == Qt::Vertical ? event->angleDelta().y(): event->angleDelta().x();
        double factor = qPow(base, angle);
        applyZoom(factor, event->pos());
    }
}

void GraphicsView::applyZoom(double factor, const QPoint & fixedViewPos)
{
    QPointF fixedScenePos = mapToScene(fixedViewPos);
    centerOn(fixedScenePos);
    scale(factor, factor);
    QPointF delta = mapToScene(fixedViewPos) - mapToScene(viewport()->rect().center());
    centerOn(fixedScenePos - delta);
}

Then using the widget promotion offered by Qt Designer is inserted into the GUI. And then set the values:

ui->rightView->setModifiers(Qt::AltModifier);
ui->leftView->setModifiers(Qt::ControlModifier);

The complete example can be found here.


On the other hand many of the code examples that are shown in SO are only to show the functionality and not necessarily be used for the implementation of the projects because having little space here is compressed sometimes losing readability. For example, I have based on the idea of the answer that you point out but I have divided it correctly to have a clean code.