0

I'm trying to use QThreading in my PyQt application. I have a worker that constantly does something in a loop and occasionally needs to update parameters used in its loop body. I decided to solve the problem using signals. However the parameter update never happens. To demonstrate the problem, consider the following code:

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *


class A(QObject):
    def run(self):
        while True:
            pass

    def update(self):
        print("Updating")


class Updater(QObject):
    update_needed = pyqtSignal()


a = A()
u = Updater()
t = QThread()
a.moveToThread(t)

t.started.connect(a.run)
t.finished.connect(a.deleteLater)
u.update_needed.connect(a.update)

t.start()
u.update_needed.emit()

At first I thought the problem was that my run method wasn't allowing the QThread enough time to process events (even though I read that QThread would ensure this automatically - this was why I chose this threading implementation with moveToThread instead of subclassing QThread).

So I changed the run method in A to

def run(self):
    return True

but update still didn't get called.

Finally, I tried putting everything in an actual QApplication (even though a QThread should have its own event loop AFAIK):

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.a = A()
        self.u = Updater()
        t = QThread(self)
        self.a.moveToThread(t)

        t.started.connect(self.a.run)
        t.finished.connect(self.a.deleteLater)
        self.u.update_needed.connect(self.a.update)

        t.start()
        self.u.update_needed.emit()


class A(QObject):
    def run(self):
        while True:
            pass

    def update(self):
        print("Updating")


class Updater(QObject):
    update_needed = pyqtSignal()


app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

but this does not run update either. Why is the update_needed signal not registering?

Mate de Vita
  • 1,102
  • 12
  • 32
  • change to `t = QThread(self)` – eyllanesc Feb 24 '20 at 18:31
  • Doing this only addresses the side problem of the "`QThread` destroyed" error message. It does not fix the key problem addressed in the question. – Mate de Vita Feb 25 '20 at 09:22
  • I have edited the original question to clarify the issue. – Mate de Vita Feb 25 '20 at 16:06
  • In both of the code examples shown `A.run` is an infinite loop that never passes control back to the Qt event processing loop. So regardless of how many queued signals are sent they will never be processed. – G.M. Feb 26 '20 at 15:15
  • `return True` is not an infinite loop. – Mate de Vita Feb 27 '20 at 09:17
  • 1
    Have you tried having `A.run` simply `return True` in the second code example you give? – G.M. Feb 27 '20 at 12:12
  • Also note that in the second example the `QThread` is local to the `MainWindow` ctor -- you need to make it a class variable with `self.t = QThread()`. – G.M. Feb 27 '20 at 12:25
  • Combining the second example with a `return True` indeed makes the `update` run. I still don't understand why the same didn't work in the first example (since `QThread` is supposed to have its own event loop), but this does solve the issue. Now to figure out how to properly replicate this in my project. – Mate de Vita Feb 27 '20 at 13:49
  • 1
    I suspect the first example didn't work with the `return True` version of `A.run` because you didn't create a `QApplication` of any sort. `QApplication` does a lot of work -- initialization etc. -- and without that a lot of Qt's functionality might not work as expected. – G.M. Feb 27 '20 at 14:01

0 Answers0