目录
前置
代码:
运行
正常运行
QThread运行报错
视频
前置
1 PySide6.QtCore.QThread - Qt for Python QThread官方文档
2 长时间任务可以放到QThread中执行,避免占用主线程导致界面卡顿无法操作
代码:
import traceback,sys
from datetime import datetime
from time import sleep
from PyQt6.QtCore import (
Qt,
QSize,
QThread,
QTime,
QObject,
pyqtSignal,
pyqtSlot
)
from PyQt6.QtWidgets import (
QApplication,
QMainWindow,
QLabel,
QPushButton,
QVBoxLayout,
QWidget,
QMessageBox
)class Worker_000(QObject):signal_finished = pyqtSignal(str) # 任务结束信号signal_error = pyqtSignal(tuple) # 任务报错信号signal_result = pyqtSignal(str) # 任务返回的结果@pyqtSlot(object)def do_work(self,task_data:dict):thread_name = task_data['thread_name']res_str = '执行结束了。'try:# work code startfor i in range(20):if i==10:raise ValueError('测试报错功能')self.signal_result.emit(f"线程返回 第{i}次,当前时间为 {QTime.currentTime().toString('hh:mm:ss')} ")sleep(1)pass# work code endpassexcept:traceback.print_exc()exctype,value = sys.exc_info()[:2]self.signal_error.emit((thread_name,exctype,value,traceback.format_exc()))passelse:self.signal_result.emit(res_str)finally:self.signal_finished.emit(thread_name)passpassclass MainWindow(QMainWindow):signal_worker = pyqtSignal(object)def __init__(self):super().__init__()self.setWindowTitle('QThread')self.setMinimumSize(QSize(600,400))self.label_worker = QLabel()self.label_main = QLabel()self.btn = QPushButton('启动QThread',clicked=self.btn_clicked)self.btn00 = QPushButton('主界面',clicked=self.btn00_clicked)layout = QVBoxLayout()layout.addWidget(self.label_worker)layout.addWidget(self.btn)layout.addWidget(self.btn00)layout.addWidget(self.label_main)widget = QWidget()widget.setLayout(layout)self.setCentralWidget(widget)self.open_init()passdef open_init(self):self.thread = Noneself.worker = Noneself.waitting_close = Falsepassdef btn_clicked(self):self.btn.setDisabled(True)self.worker = Worker_000()self.thread = QThread()self.thread.finished.connect(self.thread_finished)self.worker.signal_finished.connect(self.worker_signal_finished_emit)self.worker.signal_error.connect(self.worker_signal_error_emit)self.worker.signal_result.connect(self.worker_signal_results_emit)# 主线程与子线程之间的交互必须通过信号与槽进行,不要在主线程中通过 self.worker.do_woker()self.signal_worker.connect(self.worker.do_work)# 由于是通过 moveToThread 启动 QThread.run() ,QThread不会自动发起finished信号,需要手动 quit或exit后才会发送finishedself.worker.moveToThread(self.thread)self.thread.start()task_data = {'thread_name':'worker_000'}self.signal_worker.emit(task_data)print('线程开始了。')passdef btn00_clicked(self):now_str = datetime.now().strftime('%Y-%m-%d %H:%M:%S')if self.thread:if self.thread.isRunning():res_str = '线程正在执行中...'else:res_str = '悠闲,哈哈哈'else:res_str = '无聊中。呵呵呵'self.label_main.setText(f"{now_str} {res_str}")passdef thread_finished(self):print('线程finished')self.btn.setDisabled(False)if self.waitting_close:self.close()passpassdef worker_signal_finished_emit(self,res:str):print(f'{res} 线程任务结束。')self.thread.quit()passdef worker_signal_error_emit(self,res:tuple):# (thread_name,type,value,traceback)pre_str = f"线程 {res[0]} 报错啦。报错信息 {res[-1]}"print(pre_str)QMessageBox.information(self,'提示',pre_str,QMessageBox.StandardButton.Ok)passdef worker_signal_results_emit(self,res:str):self.label_worker.setText(res)passdef closeEvent(self, a0):answer = QMessageBox.question(self,'确认退出?','退出将中断操作,确定要退出么?',QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)if answer == QMessageBox.StandardButton.Yes:if self.thread:if self.thread.isRunning():self.waitting_close = Trueself.thread.quit()a0.ignore()QMessageBox.information(self,'提示','正在关闭线程,请稍等',QMessageBox.StandardButton.Ok)passelse:a0.accept()else:a0.accept()else:a0.ignore()passif __name__ == '__main__':app = QApplication([])mw = MainWindow()mw.show()app.exec()pass
1 主线程与QThread之间的交互必须通过信号与槽进行
2 Work_000类是要子线程执行的任务,使用 moveToThread 方法调用QThread。注意:使用moveToThread方法调用QThread,QThread不会自主发射finished信号,需要手动quit或exit才会发射finished信号。所以在主线程接收到 Work_000 signal_finished表示任务完成的信号时,手动将QThread quit或exit
3 存在QThread的程序需要考虑一种情况,就是在QThread还在执行中时,关闭主界面(主线程)的情况。所以,定义了一个 waitting_close 布尔变量,如果发生QThread还在执行,但发起关闭主界面的请求时,将 waitting_close设置为True。在 QThread 发射finished信号后,检查 watting_close 是否为True,如果为True,就将主界面关闭。
运行
正常运行
控制台打印
QThread启动后,“启动QThread"按钮不可用。QThread执行过程中,”主界面“按钮可以正常使用。
QThread执行结束后,QThread发射finished信号,“启动QThread"按钮恢复可用状态。
QThread运行报错
控制台打印
视频
PyQt6基础_QThread_哔哩哔哩_bilibili