Reputation: 105
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
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