Repository: pyqtgraph/pyqtgraph

Issue:
wheelEvent broken in RemoteGraphicsView with pyqt5
This can be reproduced with the example/RemoteGraphicsView.py demo.  Just run and try and move the mouse wheel.  It throws:

Traceback (most recent call last):
  File "/home/michel/dev/pyqtgraph/pyqtgraph/widgets/RemoteGraphicsView.py", line 115, in wheelEvent
    self._view.wheelEvent(ev.pos(), ev.globalPos(), ev.delta(), int(ev.buttons()), int(ev.modifiers()), int(ev.orientation()), _callSync='off')
AttributeError: 'QWheelEvent' object has no attribute 'delta'


It appears that .delta() has become qt4Delta and .orientation() has become qt4Orientation.


Discussion:
+1
`.delta()` is deprecated in Qt5 and has been replaced by `.angleDelta()` and `.pixelDelta()`
`.orientation()` is also deprecated and appears to have no direct replacement

Resolving patch:
diff --git a/pyqtgraph/widgets/GraphicsView.py b/pyqtgraph/widgets/GraphicsView.py
--- a/pyqtgraph/widgets/GraphicsView.py
+++ b/pyqtgraph/widgets/GraphicsView.py
@@ -326,7 +326,16 @@ def wheelEvent(self, ev):
         if not self.mouseEnabled:
             ev.ignore()
             return
-        sc = 1.001 ** ev.delta()
+        
+        delta = 0
+        if QT_LIB in ['PyQt4', 'PySide']:
+            delta = ev.delta()
+        else:
+            delta = ev.angleDelta().x()
+            if delta == 0:
+                delta = ev.angleDelta().y()
+                
+        sc = 1.001 ** delta
         #self.scale *= sc
         #self.updateMatrix()
         self.scale(sc, sc)
diff --git a/pyqtgraph/widgets/RemoteGraphicsView.py b/pyqtgraph/widgets/RemoteGraphicsView.py
--- a/pyqtgraph/widgets/RemoteGraphicsView.py
+++ b/pyqtgraph/widgets/RemoteGraphicsView.py
@@ -8,6 +8,56 @@
 import mmap, tempfile, ctypes, atexit, sys, random
 
 __all__ = ['RemoteGraphicsView']
+        
+class SerializableWheelEvent:
+    """
+    Contains all information of a QWheelEvent, is serializable and can generate QWheelEvents.
+    
+    Methods have the functionality of their QWheelEvent equivalent.
+    """
+    def __init__(self, _pos, _globalPos, _delta, _buttons, _modifiers, _orientation):
+        self._pos = _pos
+        self._globalPos = _globalPos
+        self._delta = _delta
+        self._buttons = _buttons
+        self._modifiers = _modifiers
+        self._orientation_vertical = _orientation == QtCore.Qt.Vertical
+        
+    def pos(self):
+        return self._pos
+
+    def globalPos(self):
+        return self._globalPos
+    
+    def delta(self):
+        return self._delta
+    
+    def orientation(self):
+        if self._orientation_vertical:
+            return QtCore.Qt.Vertical
+        else:
+            return QtCore.Qt.Horizontal
+    
+    def angleDelta(self):
+        if self._orientation_vertical:
+            return QtCore.QPoint(0, self._delta)
+        else:
+            return QtCore.QPoint(self._delta, 0)
+
+    def buttons(self):
+        return QtCore.Qt.MouseButtons(self._buttons)
+    
+    def modifiers(self):
+        return QtCore.Qt.KeyboardModifiers(self._modifiers)
+    
+    def toQWheelEvent(self):
+        """
+        Generate QWheelEvent from SerializableWheelEvent.
+        """
+        if QT_LIB in ['PyQt4', 'PySide']:
+            return QtGui.QWheelEvent(self.pos(), self.globalPos(), self.delta(), self.buttons(), self.modifiers(), self.orientation())
+        else:
+            return QtGui.QWheelEvent(self.pos(), self.globalPos(), QtCore.QPoint(), self.angleDelta(), self.delta(), self.orientation(), self.buttons(), self.modifiers())
 
 class RemoteGraphicsView(QtGui.QWidget):
     """
@@ -97,22 +147,34 @@ def paintEvent(self, ev):
         p.end()
         
     def mousePressEvent(self, ev):
-        self._view.mousePressEvent(int(ev.type()), ev.pos(), ev.globalPos(), int(ev.button()), int(ev.buttons()), int(ev.modifiers()), _callSync='off')
+        self._view.mousePressEvent(int(ev.type()), ev.pos(), ev.pos(), int(ev.button()), int(ev.buttons()), int(ev.modifiers()), _callSync='off')
         ev.accept()
         return QtGui.QWidget.mousePressEvent(self, ev)
 
     def mouseReleaseEvent(self, ev):
-        self._view.mouseReleaseEvent(int(ev.type()), ev.pos(), ev.globalPos(), int(ev.button()), int(ev.buttons()), int(ev.modifiers()), _callSync='off')
+        self._view.mouseReleaseEvent(int(ev.type()), ev.pos(), ev.pos(), int(ev.button()), int(ev.buttons()), int(ev.modifiers()), _callSync='off')
         ev.accept()
         return QtGui.QWidget.mouseReleaseEvent(self, ev)
 
     def mouseMoveEvent(self, ev):
-        self._view.mouseMoveEvent(int(ev.type()), ev.pos(), ev.globalPos(), int(ev.button()), int(ev.buttons()), int(ev.modifiers()), _callSync='off')
+        self._view.mouseMoveEvent(int(ev.type()), ev.pos(), ev.pos(), int(ev.button()), int(ev.buttons()), int(ev.modifiers()), _callSync='off')
         ev.accept()
         return QtGui.QWidget.mouseMoveEvent(self, ev)
         
     def wheelEvent(self, ev):
-        self._view.wheelEvent(ev.pos(), ev.globalPos(), ev.delta(), int(ev.buttons()), int(ev.modifiers()), int(ev.orientation()), _callSync='off')
+        delta = 0
+        orientation = QtCore.Qt.Horizontal
+        if QT_LIB in ['PyQt4', 'PySide']:
+            delta = ev.delta()
+            orientation = ev.orientation()
+        else:
+            delta = ev.angleDelta().x()
+            if delta == 0:
+                orientation = QtCore.Qt.Vertical
+                delta = ev.angleDelta().y()
+                
+        serializableEvent = SerializableWheelEvent(ev.pos(), ev.pos(), delta, int(ev.buttons()), int(ev.modifiers()), orientation)
+        self._view.wheelEvent(serializableEvent, _callSync='off')
         ev.accept()
         return QtGui.QWidget.wheelEvent(self, ev)
     
@@ -251,12 +313,9 @@ def mouseReleaseEvent(self, typ, pos, gpos, btn, btns, mods):
         btns = QtCore.Qt.MouseButtons(btns)
         mods = QtCore.Qt.KeyboardModifiers(mods)
         return GraphicsView.mouseReleaseEvent(self, QtGui.QMouseEvent(typ, pos, gpos, btn, btns, mods))
-
-    def wheelEvent(self, pos, gpos, d, btns, mods, ori):
-        btns = QtCore.Qt.MouseButtons(btns)
-        mods = QtCore.Qt.KeyboardModifiers(mods)
-        ori = (None, QtCore.Qt.Horizontal, QtCore.Qt.Vertical)[ori]
-        return GraphicsView.wheelEvent(self, QtGui.QWheelEvent(pos, gpos, d, btns, mods, ori))
+    
+    def wheelEvent(self, ev):
+        return GraphicsView.wheelEvent(self, ev.toQWheelEvent())
 
     def keyEvent(self, typ, mods, text, autorep, count):
         typ = QtCore.QEvent.Type(typ)


Test patch: