目錄
前置
代碼:?
運行
正常運行
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?