pyqt5线程的启动,暂停,恢复与停止

时间:2025-02-11 13:26:56

简单介绍

在pyqt5中,如果不是特别复杂的程序,不建议手动操作线程,因为有时候不知道会发生什么致命的bug,在qt中操作线程的简单说明:

QWaitCondition()用于多线程同步,一个线程调用()阻塞等待,
直到另外一个线程调用()唤醒才继续往下执行
QMutex():是锁对象

线程执行的时候需要先上锁,并在运行的时候,定义一个判断标志,如果该标志触发就执行线程的挂起,直到再次唤醒。 

案例一

主程序启动一个多线程,同时启动一个QDialog弹窗,将线程执行的结果交给dialog做展示,为了方便观察,将线程的执行结果在主程序界面跟dialog界面的QListWidget同时展示,除此之外,在dialog弹窗关闭后,也要触发线程关闭动作。

代码如下:

import sys
import time

from PyQt5 import QtCore, QtGui, QtWidgets
from  import Qt, QThread, pyqtSignal, QWaitCondition, QMutex
from  import QWidget, QApplication, QDialog, QHBoxLayout, QListWidget


class Ui_Form(object):
    def setupUi(self, Form):
        ("Form")
        (400, 300)
        self.verticalLayout_2 = (Form)
        self.verticalLayout_2.setObjectName("verticalLayout_2")
         = ()
        ("horizontalLayout")
         = ()
        (30)
        ("verticalLayout")
        spacerItem = (20, 40, , )
        (spacerItem)
        self.start_btn = (Form)
        self.start_btn.setObjectName("start_btn")
        (self.start_btn)
        self.pause_btn = (Form)
        self.pause_btn.setObjectName("pause_btn")
        (self.pause_btn)
        self.resume_btn = (Form)
        self.resume_btn.setObjectName("resume_btn")
        (self.resume_btn)
        self.stop_btn = (Form)
        self.stop_btn.setObjectName("stop_btn")
        (self.stop_btn)
        spacerItem1 = (20, 40, , )
        (spacerItem1)
        ()
         = (Form)
        ("listWidget")
        ()
        self.verticalLayout_2.addLayout()

        (Form)
        (Form)

    def retranslateUi(self, Form):
        _translate = 
        (_translate("Form", "Form"))
        self.start_btn.setText(_translate("Form", "开始"))
        self.pause_btn.setText(_translate("Form", "暂停"))
        self.resume_btn.setText(_translate("Form", "唤醒"))
        self.stop_btn.setText(_translate("Form", "停止"))


# 主程序点击后,会有弹窗
class Show_msg(QDialog):
    quit_trig = pyqtSignal()
    def __init__(self, parent=None):
        super(Show_msg, self).__init__(parent)
        ()

    def initUi(self):
        hLayout = QHBoxLayout()
        self.list_msg = QListWidget()
        (self.list_msg)
        (hLayout)
        ('弹窗显示')

    def msg_setValue(self, msg):
        self.list_msg.addItem(msg)

    def closeEvent(self, event):
        self.quit_trig.emit()       # 关闭弹窗时,发出关闭信号,让主程序的进程关闭
        ()
        pass



class ThreadStopTest(QWidget, Ui_Form):
    def __init__(self):
        super(ThreadStopTest, self).__init__()
        (self)
        ('主程序窗口')
        ()


    def handle(self):
        self.start_btn.(self.start_thread)
        self.stop_btn.(self.stop_thread)
        self.pause_btn.(self.pause_thread)
        self.resume_btn.(self.resume_thread)


    def start_thread(self):

        self.msg_dialog = Show_msg(self)     # 点击开始按钮后加载弹窗
        self.msg_dialog.show()               # 显示弹窗
        self.msg_dialog.quit_trig.connect(self.stop_thread)      # 将弹窗中的退出信号绑定到退出线程的方法上

         = My_thread()    # 实例化一个线程,i并启动
        .num_trig.connect()                   # 线程信号绑定到主程序listWidget上
        .num_trig.connect(self.msg_dialog.msg_setValue)    # 线程信号绑定到弹窗中的listWidget上
        ()

    # 暂停线程
    def pause_thread(self):
        if :
            ()

    # 唤醒线程
    def resume_thread(self):
        if :
            ()

    # 停止线程
    def stop_thread(self):
        if :
            ()
             = None
            self.msg_dialog.close()     # 停止线程时,关闭弹窗
        else:
            ('线程不存在')

    def setValue(self, v):
        (v)


class My_thread(QThread):
    num_trig = pyqtSignal(str)
    def __init__(self):
        super(My_thread, self).__init__()
        '''
        QWaitCondition()用于多线程同步,一个线程调用()阻塞等待,
        直到另外一个线程调用()唤醒才继续往下执行
        QMutex():是锁对象
        '''
        self._isPause = False
         = QWaitCondition()
         = QMutex()

    def run(self) -> None:
        a = 0
        while True:
            ()       # 上锁
            if self._isPause:
                ()
            self.num_trig.emit(f'item{a}')
            a += 1
            (2)
            ()  # 解锁

    # 线程暂停
    def pause(self):
        self._isPause = True

    # 线程恢复
    def resume(self):
        self._isPause = False
        ()


if __name__ == '__main__':
    # PyQt5高清屏幕自适应设置,以及让添加的高清图标显示清晰,不然designer导入的图标在程序加载时会特别模糊
    (Qt.AA_EnableHighDpiScaling)
    (Qt.AA_UseHighDpiPixmaps)
    app = QApplication()
    main_win = ThreadStopTest()

    main_win.show()
    (app.exec_())



案例二

主界面定义一个进度条,两个按钮,一个休眠,一个唤醒,点击休眠,线程挂起,点击恢复,线程被唤起。

案例二引用自:04-QThread子线程的创建方式与线程挂起、唤醒 | PyQt - _vscode - 博客园

from  import QThread, QWaitCondition, QMutex, pyqtSignal, Qt
from  import QWidget, QVBoxLayout, QPushButton, QProgressBar, QApplication


class Thread(QThread):
    valueChange = pyqtSignal(int)

    def __init__(self, *args, **kwargs):
        super(Thread, self).__init__(*args, **kwargs)
        self._isPause = False
        self._value = 0
         = QWaitCondition()
         = QMutex()

    def pause(self):
        self._isPause = True

    def resume(self):
        self._isPause = False
        ()

    def run(self):
        while 1:
            ()
            if self._isPause:
                ()
            if self._value > 100:
                self._value = 0
            self._value += 1
            (self._value)
            (100)
            ()


class Window(QWidget):

    def __init__(self, *args, **kwargs):
        super(Window, self).__init__(*args, **kwargs)
        layout = QVBoxLayout(self)
         = QProgressBar(self)
        ()
        (QPushButton('休眠', self, clicked=))
        (QPushButton('唤醒', self, clicked=))

         = Thread(self)
        ()
        ()

    def doWait(self):
        ()

    def doWake(self):
        ()


if __name__ == '__main__':
    import sys
    # import cgitb

    (Qt.AA_EnableHighDpiScaling)
    (Qt.AA_UseHighDpiPixmaps)
    # (format='text')

    app = QApplication()
    w = Window()
    ()
    (app.exec_())