QGestureRecognizer.registerRecognizer() crashes using PySide2
-
I'm trying to register custom gestures in a QGraphicsView using PySide2. Calling
pan_gesture_id = QGestureRecognizer.registerRecognizer(recognizer)
results in a crash without any error. I couldn't find anything in the docs specifying the process of registering a gesture recognizer using PySide2. The following example reproduces the crash:
class View(QGraphicsView): def __init__(self): super().__init__() scene = QGraphicsScene(self) scene.setSceneRect(0, 0, self.width(), self.height()) self.setScene(scene) recognizer = PanGestureRecognizer() pan_gesture_id = QGestureRecognizer.registerRecognizer(recognizer) self.grabGesture(pan_gesture_id)
am I missing anything there?
-
Hi,
Can you provide the full script you use to trigger the crash ?
By the way:
- which version of PySide2 are you using ?
- which version of Python ?
- on which OS ?
- how did you install PySide2 ?
-
@SGaist sorry, should've added that
from PySide2.QtWidgets import QMainWindow, QApplication, QGraphicsView, QGraphicsScene, QGestureRecognizer, QGesture from PySide2.QtGui import QTouchEvent from PySide2.QtCore import QEvent class PanGesture(QGesture): def __init__(self, parent=None): super().__init__(parent) self.pos = None self.press = None self.last = None class PanGestureRecognizer(QGestureRecognizer): """Not complete, just some test""" def create(self, target) -> QGesture: return PanGesture() def reset(self, state: QGesture) -> None: pass def recognize(self, state: QGesture, watched, event: QEvent) -> QGestureRecognizer.Result: if event.type() == QEvent.TouchBegin: touch_event: QTouchEvent = event if len(touch_event.touchPoints()) == 1: state.press = touch_event.touchPoints()[0] state.pos = state.press return QGestureRecognizer.MayBeGesture elif event.type() == QEvent.TouchUpdate: touch_event: QTouchEvent = event state.last = state.pos state.pos = touch_event.touchPoints()[0] return QGestureRecognizer.TriggerGesture class View(QGraphicsView): def __init__(self): super().__init__() scene = QGraphicsScene(self) scene.setSceneRect(0, 0, self.width(), self.height()) self.setScene(scene) recognizer = PanGestureRecognizer() pan_gesture_id = QGestureRecognizer.registerRecognizer(recognizer) self.grabGesture(pan_gesture_id) class ViewWindow(QMainWindow): def __init__(self): super().__init__() self.setCentralWidget(View()) if __name__ == '__main__': app = QApplication() widget = ViewWindow() widget.show() app.exec_()
see View's constructor.
- PySide2 5.15.2, installed via pip, inside python virtual environment
- Python 3.9.0
- Windows 10
the GestureRecognizer probably doesn't work, I had just quickly put that together for some tests, but since I don't see any runtime error, I assume it's not the class custom GestureRecognizer what's causing the crash
-
After converting the example to run with PyQt5:
$ python3 main.py TypeError: invalid result from PanGestureRecognizer.recognize(), NoneType cannot be converted to PyQt5.QtWidgets.Result in this context Abort trap: 6
PanGestureRecognizer.recognize is falling off the end and effectively returning None for anything other than a TouchBegin or TouchUpdate.
-
@jeremy_k yes absolutely, I didn't pay attention to that method, because it still fails if I ignore otherwise, or everything from the beginning
def recognize(self, state: QGesture, watched, event: QEvent) -> QGestureRecognizer.Result: return QGestureRecognizer.Ignore
or in the example above:
def recognize(self, state: QGesture, watched, event: QEvent) -> QGestureRecognizer.Result: if event.type() == QEvent.TouchBegin: touch_event: QTouchEvent = event if len(touch_event.touchPoints()) == 1: state.press = touch_event.touchPoints()[0] state.pos = state.press return QGestureRecognizer.MayBeGesture elif event.type() == QEvent.TouchUpdate: touch_event: QTouchEvent = event state.last = state.pos state.pos = touch_event.touchPoints()[0] return QGestureRecognizer.TriggerGesture return QGestureRecognizer.Ignore
Shouldn't that be sufficient?
-
@nutrx said in QGestureRecognizer.registerRecognizer() crashes using PySide2:
@jeremy_k yes absolutely, I didn't pay attention to that method, because it still fails if I ignore otherwise, or everything from the beginning
def recognize(self, state: QGesture, watched, event: QEvent) -> QGestureRecognizer.Result: return QGestureRecognizer.Ignore
...
Shouldn't that be sufficient?
I'm not sure what you mean here. With the addition of the default Ignore, the application displays a window and doesn't do anything noteworthy in my environment. Are you still experiencing a crash?
-
PanGestureRecognizer doesn't have an
__init__
to callQGestureRecognizer.__init__
. I vaguely recall reports of misbehavior using PyQt if a Qt object's constructor isn't invoked. This may have been limited to QObjects. It might not apply to PySide. Either way, it's an inexpensive experiment to run. QGestureRecognizer's C++ constructor is empty, but there may be some bookkeeping on the Python side. -
@jeremy_k you mean, I should try just calling QGestureRecognizer's
__init__
inPanGestureRecognizer.__init__
? I would've guessed that's ambiguous, or does instanciation lead to a direct call of the C++ parent constructor instead of the parent's__init__
in Python? However, I just tried, still no luck :/ -
class PanGestureRecognizer(QGestureRecognizer): def __init__(self): super().__init__()
This doesn't seem to be necessary with pure python classes. The wording of object.__init__ led me to believe that it was, but a test suggests that the base class __init__ is called if no derived __init__ is defined.
-
@jeremy_k
Well, in Python just like in, say, C++, if you do not define your own__init__()
(constructor in C++) the language will always cause the base class's__init__()
/constructor. If you do define your own, you must then explicitly call the base class__init__()
/constructor, in either language.in Python.[EDIT As @jeremy_k pointed out below, I was wrong to say this applies in all C++ cases. Let's leave it as: in Python, if you define any derived
__init__()
you must (should) explicitly call the base__init__()
from there; but if you do not define a derived__init__()
the base one will still be called.]I vaguely recall reports of misbehavior using PyQt if a Qt object's constructor isn't invoked
I don't know if somehow PySide2/PyQt requires you to explicitly define your own
__init__()
and call the base, unless you have some reference for that? -
@JonB said in QGestureRecognizer.registerRecognizer() crashes using PySide2:
@jeremy_k
Well, in Python just like in, say, C++, if you do not define your own__init__()
(constructor in C++) the language will always cause the base class's__init__()
/constructor. If you do define your own, you must then explicitly call the base class__init__()
/constructor, in either language.That's inaccurate for C++ base class default constructors. The compiler will insert a call to the base constructor if the programmer does not. Explicit invocation is only required if there are arguments to pass.
-
@jeremy_k
You are quite correct, and thank you for pointing this out. Partly I was unconsciously thinking of constructors with parameters, and partly I make slips as I swap between C#/C++/Python/JavaScript! I will correct my previous post, so as not to mislead. -
You may have found a bug in the PySide2 implementation. Did you check if you have the same behaviour with PySide6 ?
-
Then you should go to the bug report system and see if there's already something there. If not, please consider opening a new issue providing your minimal runnable script that shows that behaviour.
-
It's an issue on Python and it has likely not been used that much with that language. You can add a comment on the issue to remind the current assigned person that this is still not solved.