> 文章列表 > PySide6/PyQT多线程的使用

PySide6/PyQT多线程的使用

PySide6/PyQT多线程的使用

前言

上一篇文章介绍了在PySide6中使用多线程去解决PySide6/PyQT的界面卡死问题,这次来具体介绍下多线程在使用上的一些细节。

本文尝试对以下两个问题进行解决:

  • PySide6/PyQT 多线程的使用不熟悉;
  • PySide6/PyQT 的应用程序里有耗时任务,导致应用程序卡死;

值得注意的是在 PySide6/PyQT 中实现多线程,可以选择的有很多,
QObject、QThread、QRunnable、QtConcurrent 等;
但是它们在使用上都大差不差,所以在本篇文章中,挑选了 QThread 来讲解。


知识点📖📖

本文用到的几个PySide6的知识点及链接。

作用 链接
创建新线程 QThread
对象间通信的机制,允许对象发送和接收信号 Signal
用于响应Signal信号的方法 Slot

实现

QThread 多线程

使用注意事项

在使用 PySide6QThread 时,注意事项有以下几点:

  • 不要使用Python原生的线程库来实现;
  • 消息或任务结果 通过Signal信号来传递;
  • 不要在QThread调用主线程的GUI控件应用程序会进入卡死状态;
  • QThread对象必须在主线程中创建,否则程序可能会奔溃;
    • 因为PySide6是基于事件循环的框架,GUI线程子线程都运行在同一个事件循环中。如果在子线程中创建和启动QThread对象,它会尝试创建一个新的事件循环,这会导致两个事件循环并行运行,产生无法预估的结果。

代码

代码用上一篇文章中的,看这里 —《解决PySide6/PyQT的界面卡死问题(PySide6/PyQT多线程》

# -*- coding: utf-8 -*-import timeimport requestsfrom PySide6.QtCore import (QThread, Signal, Slot, QSize)
from PySide6.QtWidgets import (QApplication, QPushButton, QLabel, QVBoxLayout, QWidget)class MyThread(QThread):signal_tuple = Signal(tuple)def __init__(self, func, *args, **kwargs):super().__init__()self.func = funcself.args = argsself.count: int = kwargs.get('count')def run(self):for idx in range(1, self.count + 1):result = self.func(*self.args)time.sleep(1)# 任务完成后发出信号self.signal_tuple.emit((idx, result))class MainWindow(QWidget):def __init__(self, parent=None):super().__init__(parent=parent)self.setup_ui()#self.button.clicked.connect(self.setup_thread)def setup_ui(self):self.setWindowTitle('demo')self.resize(QSize(250, 180))# 创建一个垂直布局layout = QVBoxLayout()# 创建一个标签self.label = QLabel('This is a label => ')layout.addWidget(self.label)# 创建一个按钮self.button = QPushButton('Send Request')layout.addWidget(self.button)# 将布局设置为主窗口的布局self.setLayout(layout)# 显示窗口self.show()def setup_thread(self):self.thread_ = MyThread(self.send_request,count=10)self.thread_.signal_tuple.connect(self.thread_finished)self.thread_.start()def send_request(self):return requests.get('https://www.csdn.net/').text[:15]@Slot(tuple)def thread_finished(self, item):self.label.setText('This is a label => ' + str(item))if __name__ == '__main__':app = QApplication([])window = MainWindow()window.show()app.exec()

代码释义

MyTherad类

  • 继承了QThread
  • 创建了一个 signal_tuple信号;
  • 类接收一个func函数以及不定长的传参(这里主要传funccount
  • 重写 run方法,线程的 start() 方法被调用时,就会自动执行run方法;
  • 执行 count 次数的func,每次睡眠1秒,使用signal_tuple 将执行结果和执行次数发送出去。

MainWindow类

  • 继承了 QWidget,实现了包含一个按钮和一个标签的简单窗口;
  • setup_thread 函数中,实例化了MyThread,并将实例化后的signal_tuple信号连接到 thread_finished函数;
  • thread_finished为槽函数,当signal_tuple发出信号时,这Slot(槽函数)将被调用,并修改label 的显示。

在实例代码 以及 代码释义中可以清晰的看到,示例代码完美符合了本文中我指出来的 QThread 多线程的几个注意事项:

  • 使用Signal信号传递运行结果;
  • 在主线程中创新子线程;
  • 不在子线程中修改主线程的控件。

以上便是 QThread 多线程PySide6/PyQT 中的使用。


后话

本次分享到此结束,
see you~~🐱‍🏍🐱‍🏍