I need to implement a zooming for a QGraphicsView
on a pinch gesture (with 2 fingers) and panning along the scene with a swipe gesture (also with 2 fingers) in PyQt5.15.7 on Windows and Mac (and optimaly working for Linux aswell). I tried to achieve this with the following code:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class View(QGraphicsView):
def __init__(self, parent=None):
super().__init__(parent)
self.zoom_in_factor = 1.25
self.zoom = 10
self.zoom_step = 1
self.zoom_clamp = True
self.zoom_range = [1, 10]
self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
self.scene = QGraphicsScene()
self.scene.setSceneRect(-5000, -5000, 10000, 10000)
self.scene.addRect(0, 0, 100, 100, QPen(Qt.NoPen), QBrush(Qt.green))
self.setScene(self.scene)
def wheelEvent(self, event):
if event.modifiers() == Qt.ControlModifier:
# Check if mouse wheel up or down
if event.angleDelta().y() > 0:
zoom_factor = self.zoom_in_factor
self.zoom += self.zoom_step
else:
zoom_factor = 1 / self.zoom_in_factor
self.zoom -= self.zoom_step
# Clamping
clamped = False
if self.zoom < self.zoom_range[0]:
self.zoom = self.zoom_range[0]
clamped = True
if self.zoom > self.zoom_range[1]:
self.zoom = self.zoom_range[1]
clamped = True
if not clamped or self.zoom_clamp is False:
self.scale(zoom_factor, zoom_factor)
self.scene.update()
else:
return super().wheelEvent(event)
app = QApplication([sys.argv])
view = View()
view.show()
app.exec()
This code works as I want to on my Windows laptop (Asus ROG Flow X13). When I do a swipe gesture it calls the super method and handles it accordingly and (I don't know why) on a pinch gesture PyQt thinks that I am holding control and therefore executes the zooming part of the code. However on a MacBook (as you would expect) the super method is called always (except when I hold down cmd). Therefore the zooming does not work with a pinch gesture there but the panning works.
I've tested usingQGestures
to implement the zooming with this code:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class View(QGraphicsView):
def __init__(self, parent=None):
super().__init__(parent)
self.grabGesture(Qt.PinchGesture)
self.grabGesture(Qt.SwipeGesture)
self.scene = QGraphicsScene()
self.scene.setSceneRect(-5000, -5000, 10000, 10000)
self.scene.addRect(0, 0, 100, 100, QPen(Qt.NoPen), QBrush(Qt.green))
self.setScene(self.scene)
def event(self, event):
if event.type() == QEvent.Gesture:
return self.gestureEvent(QGestureEvent(event))
return super().event(event)
def gestureEvent(self, event):
print("Gesture event")
if event.gesture(Qt.PinchGesture):
print("Pinch gesture")
self.pinchTriggered(QPinchGesture(event.gesture(Qt.PinchGesture)))
if event.gesture(Qt.SwipeGesture):
print("Swipe gesture")
self.swipeTriggered(QSwipeGesture(event.gesture(Qt.SwipeGesture)))
print()
return True
def pinchTriggered(self, gesture):
changeFlags = gesture.changeFlags()
if changeFlags & QPinchGesture.ScaleFactorChanged:
print("Scale factor changed", gesture.scaleFactor(), gesture.totalScaleFactor(), gesture.lastScaleFactor())
def swipeTriggered(self, gesture):
pass
app = QApplication([sys.argv])
view = View()
view.show()
app.exec()
While testing with this code the following things happend on the different platforms:
On Windows no gestures are registered.
On Mac only the the pinch gesture was registered. Therefore I tried realising the zooming on Mac with a pinch gesture trying a similar approach to the official PyQt docs. This did not seem to work because the scaleFactor
, totalScaleFactor
and totalScaleFactor
of the QPinchGesture
do not change when doing the pinch gesture. They always stays at 1.0
.
Is it possible to fix this error or is there any other approach than QGesture
s to solve this problem?
I was able to achieve it by using QNativeGesture
(ZoomNativeGesture
)for MacOS and using the wheelEvent
solution for Windows. Both using simimlar logic to realize the zooming