带有QRunnable的PyQT5线程-发送双向回调的正确方法

问题描述 投票:0回答:1

From a tutorial,我已经看到信号和插槽可以用于从工作线程到主GUI线程的回调,但是我不确定如何使用信号和插槽建立双向通信。以下是我正在处理的内容:

class RespondedToWorkerSignals(QObject):
    callback_from_worker = pyqtSignal()

class RespondedToWorker(QRunnable):
    def __init__(self, func, *args, **kwargs):
        super(RespondedToWorker, self).__init__()
        self._func = func
        self.args = args
        self.kwargs = kwargs
        self.signals = RespondedToWorkerSignals()
        self.kwargs['signal'] = self.signals.callback_from_worker
        print("Created a responded-to worker")

    @pyqtSlot()
    def run(self):
        self._func(*self.args, **self.kwargs)

    @pyqtSlot()
    def acknowledge_callback_in_worker(self):
        print("Acknowledged Callback in Worker")

class MainWindow(QMainWindow):

    # Signal meant to connect to a slot present within a worker
    mainthread_callback_to_worker = pyqtSignal()

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        # Quick UI setup
        w, lay = QWidget(), QVBoxLayout()
        w.setLayout(lay)
        self.setCentralWidget(w)
        self.timer_label = QLabel("Timer Label")
        lay.addWidget(self.timer_label)
        self.btn_thread_example = QPushButton("Push Me")
        self.btn_thread_example.pressed.connect(self.thread_example)
        lay.addWidget(self.btn_thread_example)
        self.threadpool = QThreadPool()
        self.show()

        # Set up QTimer to continue in the background to help demonstrate threading advantage
        self.counter = 0
        self.timer = QTimer()
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.recurring_timer)
        self.timer.start()

    @pyqtSlot()
    def do_something(self, signal):
        # signal argument will be the callback_from_worker and it will emit to acknowledge_callback_in_mainthread
        print("do_something is sleeping briefly. Try to see if you get a locked widget...")
        time.sleep(7)
        signal.emit()

    @pyqtSlot()
    def acknowledge_callback_in_mainthread_and_respond(self):
        # this function should respond to callback_from_worker and emit a response
        print("Acknowledged Callback in Main")
        self.mainthread_callback_to_worker.emit()

    def thread_example(self):
        print("Beginning thread example")
        worker = RespondedToWorker(self.do_something)
        worker.signals.callback_from_worker.connect(self.acknowledge_callback_in_mainthread_and_respond)
    # self.mainthread_callback_to_worker.connect(worker.acknowledge_callback_in_worker) # <-- causes crash

    def recurring_timer(self):
        self.counter += 1
        self.timer_label.setText(f"Counter: {self.counter}")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = MainWindow()
    app.setStyle("Fusion")
    win.show()
    sys.exit(app.exec())

当前,脚本可以创建第二个线程,并向主GUI发送信号。我希望GUI将响应信号发送回工作线程。我也不确定为什么连接主/ GUI的信号mainthread_callback_to_worker会导致崩溃(请参见注释行)。

我知道一种解决方法是do_something返回一些值,然后在工作程序内部将其用作“确认”。但是,如果可能的话,我想了解使用信号和插槽的解决方案。

[编辑]已解决:建议有类似问题的用户参考Qt文档的本部分。简而言之,QRunnable + QThreadPool不支持基于信号的控制。从一个教程中,我已经看到...

python multithreading pyqt pyqt5 signals-slots
1个回答
0
投票

要了解错误的原因,您必须在终端中运行代码,您将收到以下错误消息:

© www.soinside.com 2019 - 2024. All rights reserved.