PySide中QThread显示子窗口时暂停运行与数据传递问题求助
解决方案
要实现线程暂停等待子窗口输入并接收数据的需求,核心是用QWaitCondition + QMutex实现线程的安全暂停/唤醒,配合信号机制让主线程弹出子窗口,输入完成后将数据传递给线程并恢复执行。
关键修改点
- 给Worker线程添加线程同步工具(QWaitCondition、QMutex),用于暂停线程等待数据。
- 新增线程槽函数接收主线程传递的输入数据,并唤醒线程。
- 主线程在收到子窗口数据后,将数据转发给Worker线程。
完整代码
from PySide2 import QtWidgets from PySide2 import QtCore import sys, time class InsertWindow(QtWidgets.QDialog): signal_return_data = QtCore.Signal(str) def __init__(self): super().__init__() self.layout = QtWidgets.QVBoxLayout() self.line = QtWidgets.QLineEdit("") self.push = QtWidgets.QPushButton("Send") self.push.clicked.connect(self.send_it) self.layout.addWidget(self.line) self.layout.addWidget(self.push) self.setLayout(self.layout) def send_it(self): if self.line.text() == '': msg = QtWidgets.QMessageBox() msg.setText("Cannot be empty!") msg.exec_() else: self.signal_return_data.emit(self.line.text()) self.close() class Window(QtWidgets.QWidget): def __init__(self): super().__init__() self.layout = QtWidgets.QVBoxLayout() self.txt = QtWidgets.QLabel("Welcome!") self.push = QtWidgets.QPushButton("Start") self.progres = QtWidgets.QProgressBar() self.layout.addWidget(self.txt) self.layout.addWidget(self.push) self.layout.addWidget(self.progres) self.setLayout(self.layout) self.push.clicked.connect(self.p_start) def show_insert_popup(self): self.insert_win = InsertWindow() self.insert_win.signal_return_data.connect(self.send_to_thread) self.insert_win.exec_() def p_start(self): self.progres.setMinimum(0) self.progres.setMaximum(0) self.worker = Worker() self.worker.signal_open_insert.connect(self.show_insert_popup) self.worker.finished.connect(self.stop_) self.worker.start() def stop_(self): self.progres.setMinimum(0) self.progres.setMaximum(100) self.txt.setText("Thread finished!") @QtCore.Slot(str) def send_to_thread(self, txt): self.txt.setText(f"Received input: {txt}") self.worker.set_data(txt) class Worker(QtCore.QThread): signal_open_insert = QtCore.Signal() def __init__(self): super().__init__() self.wait_condition = QtCore.QWaitCondition() self.mutex = QtCore.QMutex() self.received_data = None def run(self): # 第一阶段工作 for x in range(2): print("I'm working in thread (stage 1)") time.sleep(2) # 请求主线程弹出输入窗口,然后暂停等待数据 self.signal_open_insert.emit() # 线程安全的等待:加锁后等待条件触发 self.mutex.lock() self.wait_condition.wait(self.mutex) self.mutex.unlock() # 第二阶段工作,使用收到的数据 if self.received_data: for x in range(2): print(f"Here is the data from insert window: {self.received_data}") time.sleep(1) @QtCore.Slot(str) def set_data(self, data): # 线程安全的设置数据并唤醒线程 self.mutex.lock() self.received_data = data self.wait_condition.wakeOne() self.mutex.unlock() app = QtWidgets.QApplication(sys.argv) window = Window() window.show() app.exec_()
核心逻辑说明
线程暂停机制:
- Worker线程在需要等待输入时,调用
wait_condition.wait(self.mutex)进入阻塞状态,释放mutex的同时等待唤醒信号。 - 主线程传递数据时,先加锁保护共享数据
received_data,设置完成后调用wait_condition.wakeOne()唤醒线程,最后解锁。
- Worker线程在需要等待输入时,调用
数据传递流程:
- 子窗口输入完成后,通过
signal_return_data将数据发送给主线程的send_to_thread槽。 - 主线程调用Worker的
set_data槽,将数据存入线程的received_data并唤醒线程。 - 线程唤醒后,继续执行后续逻辑,直接使用
received_data。
- 子窗口输入完成后,通过
注意事项:
- 必须用QMutex配合QWaitCondition,避免线程竞态条件,确保数据设置和线程唤醒的原子性。
- 子窗口的弹窗要使用
exec_()而不是show(),这样会阻塞主线程直到窗口关闭,保证输入完成后再继续后续操作。
内容的提问来源于stack exchange,提问作者AnnAc0nda
相关产品推荐
相关产品推荐

