I'm trying to create a set of state machines to handle different tasks in my PyQt project, in the process of handling the way that graphics need to be handled on a single thread, I've created two types of state machines, a StateMachine
which must inherit QObject
and a ThreadedStateMachine
which, to avoid duplicate code, I've had inherit from both StateMachine
and QThread
.
Here is my minimally complete code to replicate the problem:
from PyQt5.QtCore import QObject, QThread
class StateMachine(QObject):
def __init__(self):
super().__init__()
class ThreadedStateMachine(StateMachine, QThread):
def __init__(self):
super().__init__()
if __name__ == "__main__":
t = ThreadedStateMachine()
I expected this to work without fail, but instead I receive this exception
QObject::connect: No such signal ThreadedStateMachine::started()
Traceback (most recent call last):
File "/snap/pycharm-community/132/helpers/pydev/pydevd.py", line 1758, in <module>
main()
File "/snap/pycharm-community/132/helpers/pydev/pydevd.py", line 1752, in main
globals = debugger.run(setup['file'], None, None, is_module)
File "/snap/pycharm-community/132/helpers/pydev/pydevd.py", line 1147, in run
pydev_imports.execfile(file, globals, locals) # execute the script
File "/snap/pycharm-community/132/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile
exec(compile(contents+"\n", file, 'exec'), glob, loc)
File "/home/aaron/.PyCharmCE2019.1/config/scratches/emerson_pmd/new/scratch_7.py", line 15, in <module>
t = ThreadedStateMachine()
File "/home/aaron/.PyCharmCE2019.1/config/scratches/emerson_pmd/new/scratch_7.py", line 11, in __init__
super().__init__()
File "/home/aaron/.PyCharmCE2019.1/config/scratches/emerson_pmd/new/scratch_7.py", line 6, in __init__
super().__init__()
File "/snap/pycharm-community/132/helpers/pydev/_pydev_bundle/pydev_monkey_qt.py", line 181, in __init__
self.started = StartedSignalWrapper(self, self.started)
File "/snap/pycharm-community/132/helpers/pydev/_pydev_bundle/pydev_monkey_qt.py", line 151, in __init__
self.original_started.connect(self._signal)
TypeError: connect() failed between started() and _signal()
What's the correct way to combine the QObject
and QThread
classes into a single object?
I am currently using threading.Thread
as a workaround, but I'd like to be able to launch a QMessageBox
from the other thread, which shows an error:
QObject::connect: Cannot queue arguments of type 'QItemSelection'
(Make sure 'QItemSelection' is registered using qRegisterMetaType().)
QBasicTimer::start: Timers cannot be started from another thread
I believe that using QThread
would work here.
Well you have a problem PyQt does not allow the double inheritance of 2 QObject, StateMachine is a QObject and QThread is also a QObject(see the docs).
I do not think the problem is caused by threading.Thread(), I suspect that this is caused because you are modifying some object that lives in a thread and is not thread-safe, the QObjects are not thread-safe so you must interact with those objects in the thread where they live, and the models are QObject.
Read: