python GUI库图形界面开发之PyQt5线程类QThread详细使用方法


Posted in Python onFebruary 26, 2020

QThread是Qt的线程类中最核心的底层类。由于PyQt的的跨平台特性,QThread要隐藏所有与平台相关的代码

要使用的QThread开始一个线程,可以创建它的一个子类,然后覆盖其它QThread.run()函数

class Thread(QThread):
  def __init __(self):
    super(Thread,self).__ init __()
  def run(self):
    #线程相关的代码
    pass

接下来创建一个新的线程

thread = Thread()
thread.start()

可以看出,PyQt的线程使用非常简单—-建立一个自定义的类(如thread),自我继承自QThread ,并实现其run()方法即可

在使用线程时可以直接得到Thread实例,调用其start()函数即可启动线程,线程启动之后,会自动调用其实现的run()的函数,该方法就是线程的执行函数

业务的线程任务就写在run()函数中,当run()退出之后线程就基本结束了,QThread有started和finished信号,可以为这两个信号指定槽函数,在线程启动和结束之时执行一段代码进行资源的初始化和释放操作,更灵活的使用方法是,在自定义的QThread实例中自定义信号,并将信号连接到指定的槽函数,当满足一定的业务条件时发射此信号

QThread类中的常用方法

方法 描述
start() 启动线程
wait() 阻止线程,直到满足如下条件之一
与此QThread对象关联的线程已完成执行(即从run返回时),如果线程完成执行,此函数返回True,如果线程尚未启动,也返回True
等待时间的单位是毫秒,如果时间是ULONG_MAX(默认值·),则等待,永远不会超时(线程必须从run返回),如果等待超时,此函数将会返回False
sleep() 强制当前线程睡眠多少秒

QThread类中的常用信号

信号 描述
started 在开始执行run函数之前,从相关线程发射此信号
finished 当程序完成业务逻辑时,从相关线程发射此信号

QThread的使用方法实例

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *


class MainWidget(QWidget):
  def __init__(self, parent=None):
    super(MainWidget, self).__init__(parent)
    #设置标题
    self.setWindowTitle('QThread多线程例子')

    #实例化多线程对象
    self.thread = Worker()

    #实例化列表控件与按钮控件
    self.listFile = QListWidget()
    self.btnStart = QPushButton('开始')

    #把控件放置在栅格布局中
    layout = QGridLayout(self)
    layout.addWidget(self.listFile, 0, 0, 1, 2)
    layout.addWidget(self.btnStart, 1, 1)

    #信号与槽函数的连接
    self.btnStart.clicked.connect(self.slotStart)
    self.thread.sinOut.connect(self.slotAdd)

  def slotAdd(self, file_inf):
    #向列表控件中添加条目
    self.listFile.addItem(file_inf)

  def slotStart(self):
    #开始按钮不可点击,线程开始
    self.btnStart.setEnabled(False)
    self.thread.start()


class Worker(QThread):
  sinOut = pyqtSignal(str)

  def __init__(self, parent=None):
    super(Worker, self).__init__(parent)
    #设置工作状态与初始num数值
    self.working = True
    self.num = 0

  def __del__(self):
    #线程状态改变与线程终止
    self.working = False
    self.wait()

  def run(self):
    while self.working == True:
      #获取文本
      file_str = 'File index{0}'.format(self.num)
      self.num += 1
      # 发射信号
      self.sinOut.emit(file_str)
      # 线程休眠2秒
      self.sleep(2)


if __name__ == '__main__':
  app = QApplication(sys.argv)
  demo = MainWidget()
  demo.show()
  sys.exit(app.exec_())

运行效果图如下

python GUI库图形界面开发之PyQt5线程类QThread详细使用方法

代码分析

在这个例子中,单击开始按钮,会在后台定时读取数据,并把返回的数据显示在界面中,首先使用以下代码进行布局,把列表控件和按钮控件放在栅格布局管理器中

#实例化列表控件与按钮控件
self.listFile = QListWidget()
self.btnStart = QPushButton('开始')

#把控件放置在栅格布局中
layout = QGridLayout(self)
layout.addWidget(self.listFile, 0, 0, 1, 2)
layout.addWidget(self.btnStart, 1, 1)

然后将按钮的clicked信号连接到槽函数,单击开始触发槽函数

self.btnStart.clicked.connect(self.slotStart)
def slotStart(self):
    #开始按钮不可点击,线程开始
    self.btnStart.setEnabled(False)
    self.thread.start()

比较复杂的是线程的信号,将线程的sinOut信号连接到slotAdd()槽函数,SlotAdd()函数负责在列表控件中动态添加字符串条目

self.thread.sinOut.connect(self.slotAdd)
def slotAdd(self,file_inf):
    #向列表控件中添加条目
    self.listFile.addItem(file_inf)

定义一个线程类,继承自QThread,当线程启动时,执行run()函数

class Worker(QThread):
  sinOut = pyqtSignal(str)

  def __init__(self, parent=None):
    super(Worker, self).__init__(parent)
    #设置工作状态与初始num数值
    self.working = True
    self.num = 0

  def __del__(self):
    #线程状态改变与线程终止
    self.working = False
    self.wait()

  def run(self):
    while self.working == True:
      #获取文本
      file_str = 'File index{0}'.format(self.num)
      self.num += 1
      # 发射信号
      self.sinOut.emit(file_str)
      # 线程休眠2秒
      self.sleep(2)

多线程失败案例

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *

global sec
sec=0

def setTime():
  global sec
  sec+=1
  #Led显示数字+1
  lcdNumber.display(sec)

def work():
  #计时器每秒计数
  timer.start(1000)
  for i in range(200000000):
    pass
  timer.stop()
if __name__ == '__main__':
  app=QApplication(sys.argv)
  top=QWidget()
  top.resize(300,120)

  #垂直布局
  layout=QVBoxLayout(top)
  #添加一个显示面板
  lcdNumber=QLCDNumber()
  layout.addWidget(lcdNumber)
  button=QPushButton('测试')
  layout.addWidget(button)

  timer=QTimer()
  #每次计时结束,触发setTime
  timer.timeout.connect(setTime)
  button.clicked.connect(work)

  top.show()
  sys.exit(app.exec_())

失败效果图如下

python GUI库图形界面开发之PyQt5线程类QThread详细使用方法

长时间停留在此界面,知道多线程任务完成后,此界面才会动,当耗时程序非常大时,就会造成程序运行失败的假象,实际还是在后台运行的,只是没有显示在主窗口的界面上,当然用户体验也就非常差,那么如何解决这个问题呢,下面实例三进行解答

分离UI主线程与工作线程实例

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

global sec
sec = 0


class WorkThread(QThread):
  #实例化一个信号对象
  trigger = pyqtSignal()

  def __int__(self):
    super(WorkThread, self).__init__()

  def run(self):
    #开始进行循环
    for i in range(2000000000):
      pass

    # 循环完毕后发出信号
    self.trigger.emit()


def countTime():
  global sec
  sec += 1
  # LED显示数字+1
  lcdNumber.display(sec)


def work():
  # 计时器每秒计数
  timer.start(1000)
  # 计时开始
  workThread.start()
  # 当获得循环完毕的信号时,停止计数
  workThread.trigger.connect(timeStop)


def timeStop():
  #定时器停止
  timer.stop()
  print("运行结束用时", lcdNumber.value())
  global sec
  sec = 0


if __name__ == "__main__":
  app = QApplication(sys.argv)
  top = QWidget()
  top.resize(300, 120)

  # 垂直布局类QVBoxLayout
  layout = QVBoxLayout(top)

  # 加显示屏,按钮到布局中
  lcdNumber = QLCDNumber()
  layout.addWidget(lcdNumber)
  button = QPushButton("测试")
  layout.addWidget(button)

  #实例化定时器与多线程类
  timer = QTimer()
  workThread = WorkThread()

  button.clicked.connect(work)
  # 每次计时结束,触发 countTime
  timer.timeout.connect(countTime)

  top.show()
  sys.exit(app.exec_())

运行效果,程序主界面的数值会每秒增加1,直到循环结束,这里就避免了主界面长时间不动的尴尬!

python GUI库图形界面开发之PyQt5线程类QThread详细使用方法

QThread线程事件处理实例

对于执行很耗时的程序来说,由于PyQt需要等待程序执行完毕才能进行下一步,这个过程表现在界面上就是卡顿,而如果需要执行这个耗时程序时不断的刷新界面。那么就可以使用QApplication.processEvents(),那么就可以一边执行耗时程序,一边刷新界面的功能,给人的感觉就是程序运行很流畅,因此QApplicationEvents()的使用方法就是,在主函数执行耗时操作的地方,加入QApplication.processEvents()

import sys,time
from PyQt5.QtWidgets import QWidget,QPushButton,QApplication,QListWidget,QGridLayout

class WinForm(QWidget):
  def __init__(self,parent=None):
    super(WinForm, self).__init__(parent)
    #设置标题与布局方式
    self.setWindowTitle('实时刷新界面的例子')
    layout=QGridLayout()

    #实例化列表控件与按钮控件
    self.listFile=QListWidget()
    self.btnStart=QPushButton('开始')

    #添加到布局中指定位置
    layout.addWidget(self.listFile,0,0,1,2)
    layout.addWidget(self.btnStart,1,1)

    #按钮的点击信号触发自定义的函数
    self.btnStart.clicked.connect(self.slotAdd)
    self.setLayout(layout)
  def slotAdd(self):
    for n in range(10):
      #获取条目文本
      str_n='File index{0}'.format(n)
      #添加文本到列表控件中
      self.listFile.addItem(str_n)
      #实时刷新界面
      QApplication.processEvents()
      #睡眠一秒
      time.sleep(1)
if __name__ == '__main__':
  app=QApplication(sys.argv)
  win=WinForm()
  win.show()
  sys.exit(app.exec_())

python GUI库图形界面开发之PyQt5线程类QThread详细使用方法

本文详细介绍了python GUI库PyQt5的线程类QThread详细使用方法,想了解更多相关知道请查看下面的相关链接

Python 相关文章推荐
python zip文件 压缩
Dec 24 Python
Python中tell()方法的使用详解
May 24 Python
Jupyter notebook远程访问服务器的方法
May 24 Python
可能是最全面的 Python 字符串拼接总结【收藏】
Jul 09 Python
Python实现的多叉树寻找最短路径算法示例
Jul 30 Python
python通过tcp发送xml报文的方法
Dec 28 Python
nohup后台启动Python脚本,log不刷新的解决方法
Jan 14 Python
Python中字符串与编码示例代码
May 20 Python
Python 利用高德地图api实现经纬度与地址的批量转换
Aug 14 Python
利用scikitlearn画ROC曲线实例
Jul 02 Python
python 如何用map()函数创建多线程任务
Apr 07 Python
Appium中scroll和drag_and_drop根据元素位置滑动
Feb 15 Python
Python处理PDF与CDF实例
Feb 26 #Python
用Python绘制漫步图实例讲解
Feb 26 #Python
Django单元测试中Fixtures的使用方法
Feb 26 #Python
python 解压、复制、删除 文件的实例代码
Feb 26 #Python
Python递归调用实现数字累加的代码
Feb 25 #Python
python烟花效果的代码实例
Feb 25 #Python
python GUI库图形界面开发之PyQt5控件QTableWidget详细使用方法与属性
Feb 25 #Python
You might like
PHP 获取目录下的图片并随机显示的代码
2009/12/28 PHP
php 获取百度的热词数据的代码
2012/02/18 PHP
php+mysqli实现将数据库中一张表信息打印到表格里的方法
2015/01/28 PHP
yii2.0框架数据库操作简单示例【添加,修改,删除,查询,打印等】
2020/04/13 PHP
PHP7 整型处理机制修改
2021/03/09 PHP
javascript对象的property和prototype是这样一种关系
2007/03/24 Javascript
IE浏览器PNG图片透明效果代码
2008/09/02 Javascript
JQuery 遮罩层实现(mask)实现代码
2010/01/09 Javascript
21个值得收藏的Javascript技巧
2014/02/04 Javascript
JSONP跨域的原理解析及其实现介绍
2014/03/22 Javascript
jquery遍历函数siblings()用法实例
2015/12/24 Javascript
AngularJS ui-router (嵌套路由)实例
2017/03/10 Javascript
angular2 ng2 @input和@output理解及示例
2017/10/10 Javascript
json对象及数组键值的深度大小写转换问题详解
2018/03/30 Javascript
VSCode中如何利用d.ts文件进行js智能提示
2018/04/13 Javascript
Vue-cli 移动端布局和动画使用详解
2020/08/10 Javascript
Python实现Tab自动补全和历史命令管理的方法
2015/03/12 Python
Python的字典和列表的使用中一些需要注意的地方
2015/04/24 Python
深入浅析python继承问题
2016/05/29 Python
快速入手Python字符编码
2016/08/03 Python
python 实现tar文件压缩解压的实例详解
2017/08/20 Python
linux环境下的python安装过程图解(含setuptools)
2017/11/22 Python
Python如何使用argparse模块处理命令行参数
2019/12/11 Python
如何基于python实现脚本加密
2019/12/28 Python
Python安装tar.gz格式文件方法详解
2020/01/19 Python
Python爬虫之Selenium实现关闭浏览器
2020/12/04 Python
python+selenium+chrome实现淘宝购物车秒杀自动结算
2021/01/07 Python
Monnier Freres中文官网:法国领先的奢侈品配饰在线零售商
2017/11/01 全球购物
KARATOV珠宝在线商店:俄罗斯珠宝品牌
2019/03/13 全球购物
办理护照介绍信
2014/01/16 职场文书
社区安全检查制度
2014/02/03 职场文书
小学毕业感言150字
2014/02/05 职场文书
成本会计实训报告
2014/11/05 职场文书
介绍信格式
2015/01/30 职场文书
Vue3 Composition API的使用简介
2021/03/29 Vue.js
redis缓存存储Session原理机制
2021/11/20 Redis