1

I would like to subclass a Python-Qt QGraphicsView object to display some images, and I want to be able to pan with mouse dragging. However, the methods QGraphicsView.translate(x,y) and QGraphicsView.CenterOn(x,y) don't work. Here's a simple sample code fragment (for simplicity I left out mouseMoveEvent):

import sys
from qtpy import QtGui, QtCore, QtWidgets

class MyView(QtWidgets.QGraphicsView):
    def __init__(self):
        QtWidgets.QGraphicsView.__init__(self)

        self.scene = QtWidgets.QGraphicsScene(self)
        self.item = QtWidgets.QGraphicsEllipseItem(-20, -10, 160, 160)
        self.scene.addItem(self.item)
        self.setScene(self.scene)
        self._drag = False
        self._pos = QtCore.QPointF(0.0, 0.0)

    def wheelEvent(self, event):
        if event.angleDelta().y() > 0:
            self.scale(1.5,1.5)   # Increase zoom
        else:
            self.scale(0.75,0.75) # Decrease zoom

    def mousePressEvent(self, event):
        self._drag = True
        self._pos = event.pos()

    def mouseReleaseEvent(self, event):
        if self._drag:
            self._drag = False
            newPos = event.pos()
            delta = self._pos - newPos
            # What the docs say work to translate:
            self.translate( delta.x(), delta.y() )

            aff = self.transform()
            print( 'isTranslating: {}, dx: {}, dy: {}'.format(aff.isTranslating(), aff.dx(), aff.dy()) )
            print( 'hozScroll: {}, vertScroll: {}'.format( self.horizontalScrollBar().value(), self.verticalScrollBar().value() ) )


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    view = MyView()
    view.show()
    sys.exit(app.exec_())

Substitute PySide2 or PyQt5 for qtpy if needed. In order to enable translation, you first have to scroll in with the mouse wheel. Then you try dragging you can see that while the affline transform matrix is changing, but the view doesn't translate.

  • 1
    Possible duplicate of [How to use the QGraphicsView's translate() function?](https://stackoverflow.com/questions/14610568/how-to-use-the-qgraphicsviews-translate-function) – Gearoid Murphy Apr 28 '19 at 00:11

1 Answers1

2

Because QGraphicsView:

http://pyside.github.io/docs/pyside/PySide/QtGui/QGraphicsView.html

is a child class of QAbstractScrollArea:

http://pyside.github.io/docs/pyside/PySide/QtGui/QAbstractScrollArea.html

QGraphicsView.translate() does move the scene, but then the parent class is called and the signals connected to the scroll bars move the scene back to the scroll-bar indicated position. One solution is to turn off the scroll bar signals:

self.setVerticalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOff )
self.setHorizontalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOff )
self.horizontalScrollBar().disconnect()
self.verticalScrollBar().disconnect()

If you want to retain the scroll bars, you have to set them directly:

self.horizontalScrollBar().setValue( self.horizontalScrollBar().value() + delta.x() )
self.verticalScrollBar().setValue( self.verticalScrollBar().value() + delta.y() )

Or possibly you could replumb the signal/slots going into them.

  • Adding self as the parameter was needed on PySide2: `self.horizontalScrollBar().disconnect(self)` `self.verticalScrollBar().disconnect(self)`. – Eftekhari Oct 08 '20 at 13:23