首页 > 解决方案 > pyqt5 QTimer.singleShot 根本不运行

问题描述

(Python 3.7.3,PyQt5m MacOS Mojave)

在下面的代码中,我希望看到

start_batch
item
item
item
item
returned from start_batch

但我实际上得到的是

start_batch
returned from start_batch

也就是说,simulated_item 永远不会运行,甚至一次也不会。

我需要做什么来纠正这个问题?

from PyQt5.QtCore import QTimer, QCoreApplication, QThread
import time, sys

class Scanner(object):
    def __init__(self):
        self.num = -1

    def start_batch(self, operator_id, update_callback):
        print('start_batch')
        self.update_callback = update_callback
        QTimer.singleShot(1, self.simulated_item)

    def simulated_item(self):
        print('item')
        self.update_callback()
        self.num += 1
        if self.num > 4:
            self.normal_stop_callback()
            return
        QTimer.singleShot(100, self.simulated_item)

class dummy(QThread):
    def update(self):
        print('update')

    def run(self):
        scnr = Scanner()
        scnr.start_batch('opid', self.update)
        print('returned from start_batch')
        for i in range(10):
            time.sleep((0.2))

app = QCoreApplication([])
thread = dummy()
thread.run()

标签: pythonpython-3.xpyqtpyqt5

解决方案


In your code you have the error that you are calling the run method directly but that is not appropriate but you have to use the start() method:

app = QCoreApplication([])
thread = dummy()
thread.start()
app.exec_()

But you still won't get what you want.

Many elements such as the case of QTimer (also the signals) need an event loop to be able to work but when you override the run method that has it by default you have eliminated it so it fails.

So an approximation of what you want may be the following code where the QTimer uses the QCoreApplication event loop:

from PyQt5.QtCore import QTimer, QCoreApplication, QThread
import time, sys


class Scanner(object):
    def __init__(self):
        self.num = -1

    def start_batch(self, operator_id, update_callback):
        print("start_batch")
        self.update_callback = update_callback
        QTimer.singleShot(1, self.simulated_item)

    def simulated_item(self):
        print("item")
        # QTimer.singleShot() is used so that the update_callback function 
        # is executed in the thread where the QObject to which it belongs lives, 
        # if it is not a QObject it will be executed in the thread 
        # where it is invoked
        QTimer.singleShot(0, self.update_callback)
        # self.update_callback()
        self.num += 1
        if self.num > 4:
            # self.normal_stop_callback()
            return
        QTimer.singleShot(100, self.simulated_item)


class dummy(QThread):
    def update(self):
        print("update")

    def run(self):
        for i in range(10):
            time.sleep(0.2)
        print("returned from start_batch")


if __name__ == "__main__":

    app = QCoreApplication(sys.argv)
    thread = dummy()
    thread.start()
    scnr = Scanner()
    thread.started.connect(lambda: scnr.start_batch("opid", thread.update))
    sys.exit(app.exec_())

推荐阅读