Rafe
Rafe

Reputation: 2065

How do I mouse-drag-zoom a QGraphicsView anchored to the mouse drag starting position?

I'm trying to click and drag to zoom in and out of a QGraphicsView like you see in graphics applications like Maya and Nuke. There is a lot of information about using the mouse wheel but I haven't found anything related to dragging to zoom.

Is there an easy way to do this or do I need to roll my own implementation of the "anchor" effect?

The following will work but the view follows the mouse around as I drag the zoom rather than appearing to zoom in and out of a fixed point in space (the point where the mouse was clicked to start the drag-zoom.

(This is a bunch of copy and paste from my more complex source code. It is intended to be illustrative though it should run)

def mousePressEvent(self, event):
    self.press_mouse_pos = event.pos()
    transform = self.transform()
    self.press_translate = [transform.m31(), transform.m32()]
    self.press_scale = transform.m11()

    if event.button() == QtCore.Qt.RightButton and \
                    event.modifiers() == QtCore.Qt.AltModifier:
        self.scaling = True
        event.accept()
    else:
        super(GraphView, self).mousePressEvent(event)

def mouseMoveEvent(self, event):
    if self.scaling:
        delta_pos = event.pos() - self.press_mouse_pos
        amount = delta_pos.x() + delta_pos.y()
        speed = 0.001
        scl = self.press_scale - (amount * speed)
        scl = min(1.0, max(scl, 0.1))  # Clamp so we don't go to far in or out

        transform = QtGui.QTransform(
            scl, 0, 0,
            0, scl, 0,
            self.press_translate[0], self.press_translate[1], 1
        )

        # If interactive is True then some double calculations are triggered
        prev_interactive_state = self.isInteractive()
        prev_anchor_mode = self.transformationAnchor()

        self.setInteractive(False)
        self.setTransformationAnchor(QtGui.QGraphicsView.AnchorUnderMouse)

        self.setTransform(transform)

        self.setInteractive(prev_interactive_state)
        self.setTransformationAnchor(prev_anchor_mode)
    else:
        super(GraphView, self).mouseMoveEvent(event)

def mouseReleaseEvent(self, event):
    self.scaling = False
    super(GraphView, self).mouseReleaseEvent(event)

Upvotes: 1

Views: 1085

Answers (1)

fkite
fkite

Reputation: 11

Change this:

    self.setTransformationAnchor(QtGui.QGraphicsView.AnchorUnderMouse)

to that:

    self.setTransformationAnchor(QtGui.QGraphicsView.NoAnchor)

setTransformation() is a subject to transformation anchor; AnchorUnderMouse makes sure that a scene point corresponding the current (at the moment when transform is applied) mouse position remains untranslated.

Upvotes: 1

Related Questions