【问题标题】:Setup signal and slot before moving Worker object to QThread in pyqt在 pyqt 中将 Worker 对象移动到 QThread 之前设置信号和槽
【发布时间】:2019-12-04 14:52:34
【问题描述】:

在 Qt/PyQt 中,我曾经使用 Worker 类和 QThread 进行线程化。

self.worker = Worker()
self.thread = QThread()

worker.moveToThread(thread)
setup_signal_slot_with_main_object()

// start 
thread.start()

我必须将 setup_signal_slot_with_main_object() 放在 moveToThread() 之后。但我有一个复杂的工人。在 Worker.__ init__() 中,它创建了许多 QObject 并连接内部信号和插槽。我不想创建一个在 worker->moveToThread(&thread) 之后建立所有连接并调用 worker.setup_signal_slot() 的方法,因为 Worker 包含许多子 QObject,每个QObject 可以在其构造函数中制作信号/槽。

在 Qt/C++ 中,我可以在 worker 的构造函数中建立信号/槽连接。但是在 PyQt 中,slot 不会在新线程中运行。

这是一个包含 QTimer 的 Worker 的示例

import sys
import signal
import threading
from PyQt5.QtCore import QObject, pyqtSignal, QTimer, QCoreApplication, QThread
import datetime


class Worker(QObject):
    timeChanged = pyqtSignal(object)

    def __init__(self, parent=None):
        QObject.__init__(self, parent)

        self.timer = QTimer(self)
        self.timer.setInterval(1000)

        # I want to make connection at here
        self.timer.timeout.connect(self.main_process)

    def start(self):
        # self.timer.timeout.connect(self.main_process)
        self.timer.start()
        print('Worker thread {}: Start timer'.format(threading.get_ident()))

    # this method still run in main thread
    def main_process(self):
        timestamp = datetime.datetime.now()
        print('Worker thread {}: {}'.format(threading.get_ident(), timestamp.strftime('%d-%m-%Y %H-%M-%S')))
        self.timeChanged.emit(timestamp)


class WorkerThread(QObject):
    def __init__(self, parent=None):
        QObject.__init__(self, parent)

        self.emitter = Worker()
        self.thread = QThread(self)
        self.emitter.moveToThread(self.thread)

        self.thread.started.connect(self.emitter.start)
        self.thread.finished.connect(self.emitter.deleteLater)
        self.emitter.timeChanged.connect(self.show_time)

    def start(self):
        self.thread.start()

    def stop(self):
        if self.thread.isRunning():
            self.thread.quit()
            self.thread.wait()
            print('Exit thread')

    def show_time(self, timestamp):
        print('Main   thread {}: {}'.format(threading.get_ident(), timestamp.strftime('%d-%m-%Y %H-%M-%S')))


def signal_handler(sig, frame):
    print('Quit')
    app.quit()


if __name__ == '__main__':
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)

    app = QCoreApplication(sys.argv)

    timer = QTimer()
    timer.timeout.connect(lambda: None)
    timer.start(500)

    print('Main    thread {}'.format(threading.get_ident()))
    emitter = WorkerThread()
    emitter.start()
    sys.exit(app.exec_())

在Worker中,定时器超时会在主线程中调用main_process。我可以将 self.timer.timeout.connect(self.main_process) 移动到方法 worker.start() 中。但正如我上面所说,我仍然想在其构造函数中放置内部信号/插槽。 谁能建议我一个解决方案?谢谢!

【问题讨论】:

    标签: python pyqt pyqt5 qthread qobject


    【解决方案1】:

    如果您希望在接收者使用pyqtSlot() 装饰器的同一线程中调用方法,如果您不这样做,那么它将在发送者的线程中调用。

    import sys
    import signal
    import threading
    import datetime
    
    from PyQt5.QtCore import QObject, pyqtSignal, QTimer, QCoreApplication, QThread, pyqtSlot
    
    
    class Worker(QObject):
        timeChanged = pyqtSignal(object)
    
        def __init__(self, parent=None):
            QObject.__init__(self, parent)
    
            self.timer = QTimer(self)
            self.timer.setInterval(1000)
    
            self.timer.timeout.connect(self.main_process)
    
        @pyqtSlot()
        def start(self):
            self.timer.start()
            print("Worker thread {}: Start timer".format(threading.get_ident()))
    
        @pyqtSlot()
        def main_process(self):
            timestamp = datetime.datetime.now()
            print(
                "Worker thread {}: {}".format(
                    threading.get_ident(), timestamp.strftime("%d-%m-%Y %H-%M-%S")
                )
            )
            self.timeChanged.emit(timestamp)
    
    
    class WorkerThread(QObject):
        def __init__(self, parent=None):
            QObject.__init__(self, parent)
    
            self.emitter = Worker()
            self.thread = QThread(self)
            self.emitter.moveToThread(self.thread)
    
            self.thread.started.connect(self.emitter.start)
            self.thread.finished.connect(self.emitter.deleteLater)
            self.emitter.timeChanged.connect(self.show_time)
    
        @pyqtSlot()
        def start(self):
            self.thread.start()
    
        def stop(self):
            if self.thread.isRunning():
                self.thread.quit()
                self.thread.wait()
                print("Exit thread")
    
        @pyqtSlot(object)
        def show_time(self, timestamp):
            print(
                "Main   thread {}: {}".format(
                    threading.get_ident(), timestamp.strftime("%d-%m-%Y %H-%M-%S")
                )
            )
    
    
    def signal_handler(sig, frame):
        print("Quit")
        app.quit()
    
    
    if __name__ == "__main__":
        signal.signal(signal.SIGINT, signal_handler)
        signal.signal(signal.SIGTERM, signal_handler)
    
        app = QCoreApplication(sys.argv)
    
        timer = QTimer()
        timer.timeout.connect(lambda: None)
        timer.start(500)
    
        print("Main    thread {}".format(threading.get_ident()))
        emitter = WorkerThread()
        emitter.start()
        sys.exit(app.exec_())
    

    输出:

    Main    thread 140175719339648
    Worker thread 140175659480832: Start timer
    Worker thread 140175659480832: 26-07-2019 04-39-42
    Main   thread 140175719339648: 26-07-2019 04-39-42
    Worker thread 140175659480832: 26-07-2019 04-39-43
    Main   thread 140175719339648: 26-07-2019 04-39-43
    Worker thread 140175659480832: 26-07-2019 04-39-44
    Main   thread 140175719339648: 26-07-2019 04-39-44
    Worker thread 140175659480832: 26-07-2019 04-39-45
    Main   thread 140175719339648: 26-07-2019 04-39-45
    

    【讨论】:

    • 非常感谢!我误解了任何 python 方法都是插槽。我应该将@pyqtSlot 添加到我的所有插槽中,尤其是对于多线程程序。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-08
    • 1970-01-01
    • 1970-01-01
    • 2012-07-13
    • 2018-09-23
    • 2022-10-04
    相关资源
    最近更新 更多