1
votes

I am stuck with this weird behavior where, if I enable rubberband drag, the wheel event doesn't zoom under mouse anymore. It does zooming but irrespective of mouse position. And if I disable other events, then wheelEvent works properly.

I have a custom class inheriting QGraphicsView as :

class MyGraphics : public QGraphicsView{

public :
    MyGraphics(QWidget *parent = NULL);

public slots:
     void zoomIn() { scale(1.2, 1.2); }
     void zoomOut() { scale(1 / 1.2, 1 / 1.2); }

protected :
   QRubberBand *rubberBand;
   QPoint       origin;
   QPointF      InitialCenterPoint;
   QPointF      CurrentCenterPoint;
   QPoint       rubberBandOrigin;
   bool         rubberBandActive;
   QPoint       LastPanPoint;
   int          _numScheduledScalings;

//if I uncomment these three event handlers, the wheelevent doesnt zoom properly!

 //  virtual void mousePressEvent(QMouseEvent *event);
 //  virtual void mouseMoveEvent(QMouseEvent *event);
 //  virtual void mouseReleaseEvent(QMouseEvent *event);
   virtual void wheelEvent(QWheelEvent *);
   virtual void resizeEvent(QResizeEvent *event);

};

The constructor :

MyGraphics::MyGraphics(QWidget *parent) : QGraphicsView(parent){
    setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);

    this->installEventFilter(this);
    this->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
    this->setResizeAnchor( QGraphicsView::AnchorUnderMouse );
    QGraphicsScene *graphScene = new QGraphicsScene(this);

    this->setScene(graphScene);
    QGraphicsItem* pEllipse = graphScene->addEllipse(0,100,50,50);
    QGraphicsItem* pRect = graphScene->addRect(200,100,50,50);

    pEllipse->setFlag(QGraphicsItem::ItemIsSelectable, true);
    pRect->setFlag(QGraphicsItem::ItemIsSelectable, true);

    setSceneRect(0, 0, 1000, 1000);
    rubberBandOrigin = QPoint(0,0);
}

Event handlers :

void MyGraphics::wheelEvent(QWheelEvent *event){
    if(event->delta() > 0){
        //Zoom in
        this->zoomIn();
    } else {
        this->zoomOut();
    }

}

/*
void MyGraphics::mousePressEvent(QMouseEvent *event)
{
        if (event->button() == Qt::MiddleButton) {
        rubberBandOrigin = event->pos();
        rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
        rubberBand->setGeometry(event->x(),event->y(),0, 0);
        rubberBand->show();
        rubberBandActive = true;
    }
if(event->button() == Qt::LeftButton){
    LastPanPoint = event->pos();
}


}

void MyGraphics::mouseMoveEvent(QMouseEvent *event)
{
    if (event->buttons() == Qt::MiddleButton && rubberBandActive == true){
        rubberBand->resize( event->x()-rubberBandOrigin.x(), event->y()-rubberBandOrigin.y() );
    }
    else{
        if(!LastPanPoint.isNull()) {
            //Get how much we panned
            QGraphicsView * view = static_cast<QGraphicsView *>(this);

            QPointF delta = view->mapToScene(LastPanPoint) - view->mapToScene(event->pos());
            LastPanPoint = event->pos();
        }
    }
}

void MyGraphics::mouseReleaseEvent(QMouseEvent *event)
{
   if (event->button() == Qt::MiddleButton){
        QGraphicsView * view = static_cast<QGraphicsView *>(this);

        QPoint rubberBandEnd = event->pos();

        QRectF zoomRectInScene = QRectF(view->mapToScene(rubberBandOrigin), view->mapToScene(rubberBandEnd));
        QPointF center = zoomRectInScene.center();

        view->fitInView(zoomRectInScene, Qt::KeepAspectRatio);
        rubberBandActive =  false;
        delete rubberBand;
    }
    else{
        LastPanPoint = QPoint();
    }
}
*/

Any idea where I am doing wrong or how do I fix it ?

1
Do you know about graphicsView->setDragMode(QGraphicsView::RubberBandDrag)? It seems that you're trying to implement what is already implemented.Pavel Strakhov
Yes I do know about it. But with rubberband also, I want to select an area with rubberband and fill the whole screen by the selected region. I don't know how to proceed with that by doing setDragMode(QGraphicsView::RubberBandDrag) . That is why I implemented a custom rubberbanddrag process.gaganbm
I don't understand the problem, but try to describe it with more details in a separate question. May be this problem has a solution and you don't have to reimplement rubber band.Pavel Strakhov
Well, I don't know what more details to give. The problem is quite straight forward. The wheelevent zooming works well (like google earth) when I comment the other mouse events, as seen in the code. If I uncomment those, the zooming doesnt work properly on wheel event.gaganbm
I was talking about the problem you've referred to in your previous comment: 'I want to select an area with rubberband and fill the whole screen by the selected region'.Pavel Strakhov

1 Answers

1
votes

QGraphicsView::scale function's behaviour depends on the mouse position. It's performing automatically and internally by QGraphicsView. Since you don't pass mouse position to the scale function, I think QGraphicsView tracks the mouse and remembers the last position on its own.

By reimplementing mouse event handlers you have taken this ability from it. The view can't determine the mouse position anymore because its original handlers aren't called.

Luckily this issue can be easily fixed. You need to call base class implementation before your own:

void MyGraphics::mousePressEvent(QMouseEvent *event) {
  QGraphicsView::mousePressEvent(event);
  // your implementation goes here
}

It's an example for mousePressEvent but you should add similar statements to all your event handlers unless you need to disable some part of default behavior.