Ulf Wållgren
Ulf Wållgren

Reputation: 171

PyQt QGraphicsView pan and zoom with transform matrix

I am trying to do pan and zoom with the QGraphics transform matrix. The zoom works fin but the pan parameters m31 and m32 have no effect. It looks like there is an another function that centers the scene. In the code below I manipulate the rectScene to do Pan but why can I not use m31 and m32 to Pan? (This is my question

'''Pan (left mouse but) and zoom (mouse wheel)  test'''
'''Python 3.4 (No differance between PyQt4 and PyQt5)'''
#from PyQt5 import QtGui, QtCore
#import PyQt5.QtWidget as QW            
from PyQt4 import QtGui, QtCore
import PyQt4.QtGui as QW            

import numpy as np                         

class ZoomAndPan(QW.QGraphicsView):

    def __init__(self,parent=None):
        super(ZoomAndPan,self).__init__(parent)
        self.setWindowTitle('ZoomAndPan')
        self.setGeometry(600,300,600,400)
        'Left button in top of image. Shows the transform matrix (press to reset)'
        self.mess = QW.QPushButton('Transform Matrix\n\n\ndx,xy\ncounter', self)
        self.mess.clicked.connect(self.resetM)

        'm31 button, adds 200 to m31'
        self.m31 = QW.QPushButton('m31', self)
        self.m31.move(200,0)
        self.m31.clicked.connect(self.addM31)

        'm13 button, adds 0.0001 to m13'
        self.m13 = QW.QPushButton('m13', self)
        self.m13.move(300,0)
        self.m13.clicked.connect(self.addM13)
        self.count=0   #Counter     

        # Create scene   
        self.sc=scene(self,self)
        self.setScene(self.sc)

    def mouseMoveEvent(self,event):
        'Pan by manipulting sceneRect'
        pos=event.pos()
        pos=self.mapToScene(pos)      
        dx=pos.x()-self.sc.startPos.x() 
        dy=pos.y()-self.sc.startPos.y()

        rect=self.sceneRect().getRect()
        self.setSceneRect(rect[0]-dx,rect[1]-dy,rect[2],rect[3])         
        # Increas counter to show that the loop works 
        self.count+=1
        self.showMatrix()

    def showMatrix(self):
        'Show matrix in Textbox (Buttton)'
        m=self.transform()
        str1='{0:5.2f}{1:5.2f} {2:6.4f}\n'.format(m.m11(), m.m12(),m.m13())
        str2='{0:5.2f}{1:5.2f}{2:5.2f}\n'.format(m.m21(), m.m22(),m.m23())
        str3='{0:5.2f}{1:5.2f}{2:5.2f}\n'.format(m.m31(), m.m32(),m.m33())
        str4='{0:5.2f}{1:5.2f}\n'.format(m.dx(), m.dy(),m.m33())
        'Show counter '
        str5='{0:5.0f}'.format(self.count)        
        self.mess.setText(str1+str2+str3+str4+str5)

    def resetM(self):
        'Reset transform'
        self.resetTransform()
        self.showMatrix()

    def addM31(self):
        'Add 200 to m31 '
        m=self.transform()
        m.setMatrix(m.m11(),m.m12(),m.m13(),m.m21(),m.m22(),m.m23(),m.m31()+200,m.m32(),m.m33())
        self.setTransform(m)    
        self.showMatrix()

    def addM13(self):
        'Add 0.0001 to m13 '
        m=self.transform()
        m.setMatrix(m.m11(),m.m12(),m.m13()+0.0001,m.m21(),m.m22(),m.m23(),
            m.m31(),m.m32(),m.m33())
        self.setTransform(m)    
        self.showMatrix()        

class scene(QW.QGraphicsScene):
    def __init__(self,parent,myView=[]):
        QW.QGraphicsScene.__init__(self,parent)
        self.myView=myView        
        # Some items in scene 
        self.txt=self.addSimpleText("///////")
        self.txt.setPos(2,-20)
        self.txt.setScale(2)
        self.txt.setBrush(QtGui.QBrush(QtCore.Qt.green))
        self.addRect(0,16,20,20, pen=QtGui.QPen(QtCore.Qt.blue))
        self.addRect(10,60,32,8, pen=QtGui.QPen(QtCore.Qt.red))
        self.addRect(30,16,20,20, pen=QtGui.QPen(QtCore.Qt.blue))
        self.N=0

    def mousePressEvent(self, event):     
        self.myView.setDragMode(1) # Works fine without this   
        self.startPos=event.scenePos()        

    def mouseReleaseEvent(self, event):     
        self.myView.setDragMode(0)

    def wheelEvent(self, event):
        'zoom'
        sc=event.delta()/100
        if sc<0: sc=-1/sc
        self.myView.scale(sc,sc)
        self.myView.setDragMode(0)
        self.myView.showMatrix()        

def main():
    app = QW.QApplication([])
    fig=ZoomAndPan()
    fig.show();
    app.exec_()


if __name__=='__main__':
    main()

Upvotes: 3

Views: 3834

Answers (1)

user3419537
user3419537

Reputation: 5000

From a mathematical point of view everything is working fine. The reason you see no changes is because QGraphicsView centers the view according to its alignment property.

From the Qt docs:

QGraphicsView supports affine transformations, using QTransform. You can either pass a matrix to setTransform(), or you can call one of the convenience functions rotate(), scale(), translate() or shear(). The most two common transformations are scaling, which is used to implement zooming, and rotation. QGraphicsView keeps the center of the view fixed during a transformation. Because of the scene alignment (setAligment()), translating the view will have no visual impact.

Upvotes: 2

Related Questions