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不支持基于信号的控制。从一个教程中,我已经看到...
要了解错误的原因,您必须在终端中运行代码,您将收到以下错误消息: