grillaB
grillaB

Reputation: 105

subclassing QGraphicsView and using mouseMoveEvent and mouseClickEvent messes up moving QGraphicsItems in my scene

Pyside2: I'm subclassing QGraphicsView and adding zoom and pan functionality to mouseClickEvent and mouseMoveEvent.

When I do this the QGraphicsItems in my scene that have Selectable and Moveable enabled don't move properly after the first click and drag.

They move fine with the first click and drag but if I click and drag them again they snap back to the position they were created at and move from there.

Here is what I have:

class ZoomView(QGraphicsView):
    '''
    View class with zoom enabled
    '''
    def __init__(self):
        super(ZoomView, self).__init__()
        self.alt_key = False
        self.ctrl_key = False
        self.mid_button = False
        self.left_button = False

        self.mouse_pos = None
        self.orig_pos = None

        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(2)
        sizePolicy.setHeightForWidth(True)

        self.setSizePolicy(sizePolicy)
        self.setMinimumSize(QtCore.QSize(0, 0))
        self.setRenderHints(QtGui.QPainter.Antialiasing | QtGui.QPainter.TextAntialiasing)

        self.setResizeAnchor(QGraphicsView.NoAnchor)
        self.setObjectName("PickerView")
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)

        self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)

    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Alt:
            self.alt_key = True
        elif event.key() == QtCore.Qt.Key_Control:
            self.ctrl_key = True
        else:
            return super(ZoomView, self).keyPressEvent(event)

    def keyReleaseEvent(self, event):
        if event.key() == QtCore.Qt.Key_Alt:
            self.alt_key = False
        elif event.key() == QtCore.Qt.Key_Control:
            self.ctrl_key = False
        else:
            return super(ZoomView, self).keyReleaseEvent(event)

    def mousePressEvent(self, event):

        self.mouse_pos = event.pos()
        if event.button() == QtCore.Qt.MidButton:
            self.mid_button = True

        if event.button() == QtCore.Qt.LeftButton:
            super(ZoomView, self).mousePressEvent(event)
            self.left_button = True

    def mouseReleaseEvent(self, event):
        if event.button() == QtCore.Qt.MidButton:
            self.mid_button = False
        elif event.button() == QtCore.Qt.LeftButton:
            self.left_button = False
        else:
            return super(ZoomView, self).mouseReleaseEvent(event)

    def mouseMoveEvent(self, event):

        if event.buttons() == QtCore.Qt.NoButton:
            return super(ZoomView, self).mouseMoveEvent(event)

        new_pos = event.pos()
        diff_x = self.mouse_pos.x() - new_pos.x()
        diff_y = self.mouse_pos.y() - new_pos.y()
        if self.alt_key and self.mid_button and not self.left_button:
            # pan the screen

            h_scroll = self.horizontalScrollBar()
            v_scroll = self.verticalScrollBar()

            H_scrollFinal = h_scroll.value() + diff_x
            V_scrollFinal = v_scroll.value() + diff_y
            h_scroll.setValue(H_scrollFinal)
            v_scroll.setValue(V_scrollFinal)

            self.mouse_pos = new_pos

        elif self.alt_key and self.left_button and self.mid_button:
            # zoom
            actualScale = self.transform().m11()
            coefDdiff_x = diff_x * 0.004
            scaleFactor = actualScale - coefDdiff_x
            if scaleFactor > 0.05 and scaleFactor < 3:
                matrice = QtGui.QTransform(scaleFactor, 0, 0, 0, scaleFactor, 0, 0, 0, 1)
                self.setTransform(matrice, combine=False)
                h_scroll = self.horizontalScrollBar()
                v_scroll = self.verticalScrollBar()

                self.mouse_pos = new_pos

        else:
            return super(ZoomView, self).mouseMoveEvent(event)

Upvotes: 0

Views: 449

Answers (1)

grillaB
grillaB

Reputation: 105

Ok found a solution.

When you subclass QGraphicsView and override these mouse methods

mousePressEvent()
mouseMoveEvent()
mouseReleaseEvent()

you need to put an "if" statement at the beginning of each method that checks to see if the mouse if over one of your items before running your custom zoom/pan code. If the mouse is over an item like a rect or ellipse then just run the super of that method and return. Also if a rect or ellipse is selected then run the super and return.

Here is an example:

class MyView(QGraphicsView):

    def mousePressEvent(self, event):

        # check if clicking on a button first or if a button is selected
        scene = self.scene()
        items = scene.items(event.localPos())

        if self.selected_items():
            super(Picker_View, self).mousePressEvent(event)
            return

        if items and isinstance(items[0], Ellipse_Button):
            # QGraphicsScene.mousePressEvent(self, event)
            super(Picker_View, self).mousePressEvent(event)
            return

        self.foo()

    def selected_items(self):
        '''
        Checks if any items in the graphics scene are selected
        Returns:
            (boolean)

        '''
        scene = self.scene()
        elements = scene.items()
        for element in elements:
            if element.isSelected():
                return True
            else:
                pass
        return False

Upvotes: 1

Related Questions