0

By default 3D visualizations mouse interaction of pyqtgraph has pan event on [mouse wheel pressing + dragging], how to set such pan event on [right mouse button + drag]?

Seems like it should be some kind of combination of mousePressEvent and mouseMoveEvent or just eventFilter(self, source, event)

My pyqtgraph openGLWidget placed on PyQt5 form, so looks like such event should inhered openGLWidget from inside QMainWindow class.

But I'm not sure how to make such event filter.

Some pseudo code initial thoughts:

class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        uic.loadUi(_UI, self) 
        axis = gl.GLAxisItem()
        self.openGLWidget.addItem(axis)
    ...
    ...

    def eventFilter(self, source, event):
        if (event.type() == QtCore.QEvent.KeyPress):
           ...
        ...
        return super(openGLWidget, self).eventFilter(source, event)

enter image description here

Nick PV
  • 415
  • 6
  • 14
  • 1
    I don't know how it works on PyQt but in other GUIs when you get event like `mouseMoveEvent` then it has also information about pressed mouse buttons and it doesn't need `mousePressEvent`. Like in [Why mouseMoveEvent does nothing in PyQt5](https://stackoverflow.com/questions/35992088/why-mousemoveevent-does-nothing-in-pyqt5) – furas Aug 25 '20 at 13:32
  • @furas yep it's kinda works, not as sharp as original pan function but at least after some modification it's working. thanks for the hint. – Nick PV Aug 27 '20 at 06:57

1 Answers1

1

could be like this:

class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        uic.loadUi(_UI, self)  # Load the .ui file 

        axis = gl.GLAxisItem()
        grid = gl.GLGridItem()
        grid.scale(100, 100, 100)
        self.openGLWidget.addItem(grid)
        self.openGLWidget.addItem(axis)
        
        # installEventFilter
        self.openGLWidget.installEventFilter(self) 
        
    def eventFilter(self, source, event):
        if event.type() == QtCore.QEvent.MouseMove:
            if event.buttons() == QtCore.Qt.NoButton:
                print("Simple mouse motion")
                pass
            elif event.buttons() == QtCore.Qt.LeftButton:
                # print("Left click drag")
                pass
            elif event.buttons() == QtCore.Qt.RightButton:
                coef = 20  # Responsiveness of the pan

                xx = ((self.openGLWidget.size().width())/2)/coef
                yy = ((self.openGLWidget.size().height())/2)/coef
                self.pan((event.x()/coef)-xx, (event.y()/coef)-yy, 0)
                self.openGLWidget.updateGL()  
                # print("Right click drag")


        elif event.type() == QtCore.QEvent.MouseButtonPress:
            if event.button() == QtCore.Qt.RightButton:
                pass
                # print("Press!")
        return super(MainWindow, self).eventFilter(source, event)
    
    def pan(self, dx, dy, dz, relative='view'):
        """
        Moves the center (look-at) position while holding the camera in place. 
        
        ==============  =======================================================
        *relative*      String that determines the direction of dx,dy,dz. 
        
                        If "global", then the global coordinate system is used.
                        If "view", then the z axis is aligned with the view
                        If "view-upright", then x is in the global xy plane and
                        
                        points to the right side of the view, y is in the
                        global xy plane and orthogonal to x, and z points in
                        the global z direction.
        """
        # for backward compatibility:
        relative = {True: "view-upright", False: "global"}.get(relative, relative)
        
        if relative == 'global':
            self.openGLWidget.opts['center'] += QtGui.QVector3D(dx, dy, dz)
        elif relative == 'view-upright':
            cPos = self.openGLWidget.cameraPosition()
            cVec = self.openGLWidget.opts['center'] - cPos
            dist = cVec.length()  ## distance from camera to center
            xDist = dist * 2. * np.tan(0.5 * self.openGLWidget.opts['fov'] * np.pi / 180.)  ## approx. width of view at distance of center point
            xScale = xDist / self.width()
            zVec = QtGui.QVector3D(0,0,1)
            xVec = QtGui.QVector3D.crossProduct(zVec, cVec).normalized()
            yVec = QtGui.QVector3D.crossProduct(xVec, zVec).normalized()
            self.openGLWidget.opts['center'] = self.openGLWidget.opts['center'] + xVec * xScale * dx + yVec * xScale * dy + zVec * xScale * dz
        elif relative == 'view':
            # pan in plane of camera
            elev = np.radians(self.openGLWidget.opts['elevation'])
            azim = np.radians(self.openGLWidget.opts['azimuth'])
            fov = np.radians(self.openGLWidget.opts['fov'])
            dist = (self.openGLWidget.opts['center'] - self.openGLWidget.cameraPosition()).length()
            fov_factor = np.tan(fov / 2) * 2
            scale_factor = dist * fov_factor / self.width()
            z = scale_factor * np.cos(elev) * dy
            x = scale_factor * (np.sin(azim) * dx - np.sin(elev) * np.cos(azim) * dy)
            y = scale_factor * (np.cos(azim) * dx + np.sin(elev) * np.sin(azim) * dy)
            self.openGLWidget.opts['center'] += QtGui.QVector3D(x, -y, z)
        else:
            raise ValueError("relative argument must be global, view, or view-upright")
        
        self.update()
Nick PV
  • 415
  • 6
  • 14