如何实现PyQt5耗时代码执行期间持续显示等待窗口?
解决PyQt5中耗时任务运行时显示等待窗口的问题
嘿,我懂你想要实现的效果——在耗时代码执行完成前,让一个等待窗口一直显示,而且不能让UI假死对吧?直接在主线程里跑耗时函数(哪怕是替换掉time.sleep(2))都会卡住Qt的事件循环,导致等待窗口要么不显示,要么显示了也没法正常更新。咱们用QThread把耗时任务放到子线程里就能完美解决这个问题,下面是完整的实现方案:
核心思路
- 把耗时任务从主线程剥离到独立的子线程中,避免阻塞UI事件循环
- 用Qt的信号与槽机制,让子线程在任务完成时通知主线程关闭等待窗口
- 等待窗口在主线程中显示,因为UI操作必须在主线程执行
完整代码示例
from PyQt5.QtWidgets import (QPushButton, QApplication, QMainWindow, QDialog, QVBoxLayout, QLabel) from PyQt5.QtCore import QThread, pyqtSignal import sys import time # 定义耗时任务的线程类 class WorkerThread(QThread): # 定义任务完成的信号 task_finished = pyqtSignal() def run(self): # 这里替换成你的实际耗时函数 print("开始执行耗时任务...") time.sleep(5) # 模拟耗时操作,替换成你的业务代码 print("耗时任务执行完成!") # 发送任务完成信号 self.task_finished.emit() # 等待窗口类 class MyWarnings(QDialog): '''Generic popup window with text.''' def __init__(self): super(MyWarnings, self).__init__() self.setWindowTitle("请稍候") self.setFixedSize(200, 100) widget = QLabel('正在处理,请等待...') layout = QVBoxLayout() layout.addWidget(widget) self.setLayout(layout) # 主窗口类 class MainWindow(QMainWindow): def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.setWindowTitle("主窗口") self.setFixedSize(300, 200) self.btn = QPushButton('启动耗时任务', self) self.btn.clicked.connect(self.start_long_task) self.btn.move(100, 80) def start_long_task(self): # 创建并显示等待窗口 self.wait_dialog = MyWarnings() self.wait_dialog.show() # 创建工作线程 self.worker = WorkerThread() # 连接线程完成信号到关闭等待窗口的槽函数 self.worker.task_finished.connect(self.wait_dialog.close) # 连接线程完成信号到线程自身的删除(避免内存泄漏) self.worker.task_finished.connect(self.worker.deleteLater) # 启动线程 self.worker.start() if __name__ == '__main__': app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec_())
关键细节说明
- WorkerThread类:专门用来执行耗时任务,
run()方法里就是你的业务代码,任务完成时通过task_finished信号通知主线程 - 等待窗口MyWarnings:简单的提示窗口,在主线程中显示,不会被阻塞
- 信号与槽的连接:线程完成时自动关闭等待窗口,同时清理线程对象避免内存泄漏
- 为什么不用time.sleep在主线程:因为Qt的UI事件循环在主线程,一旦主线程被耗时任务占用,就没法处理窗口的绘制、用户交互等事件,导致窗口假死
这样修改后,等待窗口会正常显示直到耗时任务完成,而且整个UI不会卡顿~
内容的提问来源于stack exchange,提问作者ignoring_gravity
相关产品推荐
相关产品推荐

