简单介绍
在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_())