PyQt5 多线程实例

前言

PyQt的所有窗口都在UI主线程中,也就是main函数中执行了QApplication.exec_()的线程中,在该线程中执行耗时较长的操作时,会导致当前窗口停止响应。为了避免上述情况发生,需要用QThread开启一个子线程去完成耗时的操作。

问题描述

在实现数据清洗工具时,数据量通常很大,清洗过程会比较耗时,当点击执行后,当前窗口会卡住,有个圈不停再转,直到清洗任务执行完成,用户体验非常不好。
在这里插入图片描述

问题解决

通过QThread为清洗操作创建一个线程,在主线程中触发该线程执行。
子线程创建:

from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QMessageBox
from .data_clean import filter_bad, filter_blurred, filter_similar, classify_vehcolor, classify_day_or_night


class WorkThread(QThread):
    finish_trigger = pyqtSignal(int)

    def __init__(self, dir_path, task_index):
        super(WorkThread, self).__init__()
        self.dir_path = dir_path
        self.task_index = task_index

    def run(self):
        self.run_task()

    def run_task(self):
        print(self.task_index, self.dir_path)
        # 去除损坏图片
        if self.task_index == 1:
            filter_bad_number = filter_bad(self.dir_path)
            self.finish_trigger.emit(filter_bad_number)
        # 去除模糊图片
        elif self.task_index == 2:
            filter_blurred_number = filter_blurred(self.dir_path)
            self.finish_trigger.emit(filter_blurred_number)
        # 去除相似度较高图片
        elif self.task_index == 3:
            filter_similar_number = filter_similar(self.dir_path)
            print(filter_similar_number)
            self.finish_trigger.emit(filter_similar_number)
        # 机动车ORI图像颜色分类
        elif self.task_index == 4:
            classify_number = classify_vehcolor(self.dir_path)
            print(classify_number)
            self.finish_trigger.emit(classify_number)
        # 昼夜分类
        elif self.task_index == 5:
            classify_number = classify_day_or_night(self.dir_path)
            print(classify_number)
            self.finish_trigger.emit(classify_number)

注意自定义信号带参数的书写格式:
finish_trigger = pyqtSignal(int) # 自定义信号
self.finish_trigger.emit(classify_number) # 发送信号

主线程中实例化子线程并触发执行,截取部分代码如下:

class CleanDataDialog(QWidget, Ui_Dialog):
    def __init__(self, parent=None):
        super(CleanDataDialog, self).__init__(parent)
        self.setupUi(self)
        
        self.pushButton_runClean.clicked.connect(self.run_clean)

    def closeEvent(self, event):
        event.accept()
        with open('./log.txt', 'a+', encoding='utf-8') as f:
            print(self.textEdit_dataInfo.toPlainText())
            f.writelines(self.textEdit_dataInfo.toPlainText())
        self.lineEdit_showDir.setText('')
        self.textEdit_dataInfo.setText('')
        # self.pushButton_chooseDir.setDisabled(False)
        self.comboBox_cleanItem.setCurrentIndex(0)
        self.pushButton_runClean.setDisabled(False)

    def run_clean(self):
        if self.comboBox_cleanItem.currentIndex() == 0:
            QMessageBox.warning(self, '提示', '请先选择清洗选项!', QMessageBox.Ok)
            return
        if self.lineEdit_showDir.text() == '':
            QMessageBox.warning(self, '提示', '请先选择路径!', QMessageBox.Ok)
            return
        self.pushButton_runClean.setDisabled(True)
        reply = QMessageBox.question(self, '提示', '该操作将需要一定的时间,确定开始吗?', QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.Yes)
        if reply == QMessageBox.No:
            self.pushButton_runClean.setDisabled(False)
            return
        else:
            my_thread = WorkThread(self.lineEdit_showDir.text(), self.comboBox_cleanItem.currentIndex())
            my_thread.finish_trigger.connect(self.msg)
            my_thread.run()

    def msg(self, number):
        self.pushButton_runClean.setDisabled(False)
        # 去除损坏图片
        if self.comboBox_cleanItem.currentIndex() == 1:
            self.textEdit_dataInfo.append('损坏图片已去除,共 %d 张,并放入到filter_bad目录下!\r\n' % number)
            QMessageBox.information(self, '提示', '损坏图片已去除,共 %d 张,已放入到filter_bad目录下!' % number,
                                    QMessageBox.Ok)

主要代码:
my_thread = WorkThread(self.lineEdit_showDir.text(), self.comboBox_cleanItem.currentIndex())
my_thread.finish_trigger.connect(self.msg)
my_thread.run()

猜你喜欢

转载自blog.csdn.net/jane_xing/article/details/123424123
今日推荐