PyQt5中多线程模块QThread使用方法的实现


Posted in Python onJanuary 31, 2020

本文主要讲解使用多线程模块QThread解决PyQt界面程序唉执行耗时操作时,程序卡顿出现的无响应以及界面输出无法实时显示的问题。用户使用工具过程中出现这些问题时会误以为程序出错,从而把程序关闭。这样,导致工具的用户使用体验不好。下面我们通过模拟上述出现的问题并讲述使用多线程QThread模块解决此类问题的方法。

PyQt程序卡顿和无法实时显示问题现象

使用PyQt界面程序,点击运行按钮后,程序在显示框中每秒打印1个数字。程序代码如下:

# -*- coding: utf-8 -*-

import sys
import time
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QApplication, QMainWindow
from QThread_Example_UI import Ui_Form

class MyMainForm(QMainWindow, Ui_Form):
  def __init__(self, parent=None):
    super(MyMainForm, self).__init__(parent)
    self.setupUi(self)
    self.runButton.clicked.connect(self.display)

  def display(self):
    for i in range(20):
      time.sleep(1)
      self.listWidget.addItem(str(i))

if __name__ == "__main__":
  app = QApplication(sys.argv)
  myWin = MyMainForm()
  myWin.show()
  sys.exit(app.exec_())

程序运行过程结果如下(点击Run按钮后界面出现 未响应 字样 同时程序也没有出现每隔1秒打印1个数字,实际结果是循环结束后20个数字一同展示):

PyQt5中多线程模块QThread使用方法的实现 

PyQt5中多线程模块QThread使用方法的实现

问题分析

上述实现的GUI程序都是单线程运行,对于需要执行一个特别耗时的操作时就会出现该问题现象。要解决这种问题可以考虑使用多线程模块QThread。

多线程模块QThread基本原理

QThread是Qt的线程类中最核心的底层类。由于PyQt的的跨平台特性,QThread要隐藏所有与平台相关的代码 要使用的QThread开始一个线程,可以创建它的一个子类,然后覆盖其它QThread.run()函数。

class Thread(QThread):
  def __init__(self):
    super(Thread,self).__init__()
  def run(self):
    #

接下来创建一个新的线程

thread = Thread()
thread.start()

可以看出,PyQt的线程使用非常简单,建立一个自定义的类(如Thread),自我继承自QThread ,并实现其run()方法即可。在使用线程时可以直接得到Thread实例,调用其start()函数即可启动线程,线程启动之后,会自动调用其实现的run()的函数,该方法就是线程的执行函数 。

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

QThread类中的常用方法

  start():启动线程

  wait():阻止线程,直到满足如下条件之一

(1)与此QThread对象关联的线程已完成执行(即从run返回时),如果线程完成执行,此函数返回True,如果线程尚未启动,也返回True

(2)等待时间的单位是毫秒,如果时间是ULONG_MAX(默认值·),则等待,永远不会超时(线程必须从run返回),如果等待超时,此函数将会返回False

  sleep():强制当前线程睡眠多少秒

QThread类中的常用信号

  started: 在开始执行run函数之前,从相关线程发射此信号

finished:当程序完成业务逻辑时,从相关线程发射此信号

使用QThread重新实现程序解决问题

先继承QThread类并重新实现其中的run()函数,也就是说把耗时的操作放入run()函数中。代码如下:

# -*- coding: utf-8 -*-

import sys
import time
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QApplication, QMainWindow
from QThread_Example_UI import Ui_Form

class MyMainForm(QMainWindow, Ui_Form):
  def __init__(self, parent=None):
    super(MyMainForm, self).__init__(parent)
    self.setupUi(self)
    # 实例化线程对象
    self.work = WorkThread()
    self.runButton.clicked.connect(self.execute)

  def execute(self):
    # 启动线程
    self.work.start()
    # 线程自定义信号连接的槽函数
    self.work.trigger.connect(self.display)

  def display(self,str):
    # 由于自定义信号时自动传递一个字符串参数,所以在这个槽函数中要接受一个参数
    self.listWidget.addItem(str)

class WorkThread(QThread):
  # 自定义信号对象。参数str就代表这个信号可以传一个字符串
  trigger = pyqtSignal(str)

  def __int__(self):
    # 初始化函数
    super(WorkThread, self).__init__()

  def run(self):
    #重写线程执行的run函数
    #触发自定义信号
    for i in range(20):
      time.sleep(1)
      # 通过自定义信号把待显示的字符串传递给槽函数
      self.trigger.emit(str(i))

if __name__ == "__main__":
  app = QApplication(sys.argv)
  myWin = MyMainForm()
  myWin.show()
  sys.exit(app.exec_())

程序运行结果如下(实现了每隔1秒打印1个数字):

PyQt5中多线程模块QThread使用方法的实现

小结

如果你实现的工具需要执行特别耗时的操作,可以参考使用本文多线程QThread处理方法实现。当然,工具实际实现过程中的场景会比这复杂。比如,你的输出并不是有固定时间间隔输出的文本框,可以尝试使用多次self.trigger.emit(str)方法进行操作。

附录

1、使用pyuic5转换界面.ui程序后的QThread_Example_UI.py代码如下:

# -*- coding: utf-8 -*-

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Form(object):
  def setupUi(self, Form):
    Form.setObjectName("Form")
    Form.resize(498, 331)
    self.runButton = QtWidgets.QPushButton(Form)
    self.runButton.setGeometry(QtCore.QRect(190, 30, 75, 23))
    self.runButton.setObjectName("runButton")
    self.listWidget = QtWidgets.QListWidget(Form)
    self.listWidget.setGeometry(QtCore.QRect(30, 70, 431, 192))
    self.listWidget.setObjectName("listWidget")

    self.retranslateUi(Form)
    QtCore.QMetaObject.connectSlotsByName(Form)

  def retranslateUi(self, Form):
    _translate = QtCore.QCoreApplication.translate
    Form.setWindowTitle(_translate("Form", "Qthread Example"))
    self.runButton.setText(_translate("Form", "Run"))

 2、Qtdesigner设计的界面源程序代码QThread_Example_UI.ui如下:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Form</class>
 <widget class="QWidget" name="Form">
 <property name="geometry">
  <rect>
  <x>0</x>
  <y>0</y>
  <width>498</width>
  <height>331</height>
  </rect>
 </property>
 <property name="windowTitle">
  <string>Qthread Example</string>
 </property>
 <widget class="QPushButton" name="runButton">
  <property name="geometry">
  <rect>
   <x>190</x>
   <y>30</y>
   <width>75</width>
   <height>23</height>
  </rect>
  </property>
  <property name="text">
  <string>Run</string>
  </property>
 </widget>
 <widget class="QListWidget" name="listWidget">
  <property name="geometry">
  <rect>
   <x>30</x>
   <y>70</y>
   <width>431</width>
   <height>192</height>
  </rect>
  </property>
 </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
详解Python中的join()函数的用法
Apr 07 Python
解决Python中由于logging模块误用导致的内存泄露
Apr 23 Python
使用Python的Tornado框架实现一个Web端图书展示页面
Jul 11 Python
Python 中开发pattern的string模板(template) 实例详解
Apr 01 Python
Python实现的直接插入排序算法示例
Apr 29 Python
python 编写简单网页服务器的实例
Jun 01 Python
numpy给array增加维度np.newaxis的实例
Nov 01 Python
Django中使用session保持用户登陆连接的例子
Aug 06 Python
Python处理session的方法整理
Aug 29 Python
flask框架配置mysql数据库操作详解
Nov 29 Python
Python 基于jwt实现认证机制流程解析
Jun 22 Python
解决Keras的自定义lambda层去reshape张量时model保存出错问题
Jul 01 Python
浅谈python之自动化运维(Paramiko)
Jan 31 #Python
为什么黑客都用python(123个黑客必备的Python工具)
Jan 31 #Python
Win10里python3创建虚拟环境的步骤
Jan 31 #Python
python判断链表是否有环的实例代码
Jan 31 #Python
python爬取王者荣耀全皮肤的简单实现代码
Jan 31 #Python
Python进阶之迭代器与迭代器切片教程
Jan 29 #Python
Python列表list操作相关知识小结
Jan 29 #Python
You might like
Mysql的Root密码忘记,查看或修改的解决方法(图文介绍)
2013/06/14 PHP
php读取远程gzip压缩网页的方法
2014/12/29 PHP
ThinkPHP框架整合微信支付之Native 扫码支付模式二图文详解
2019/04/09 PHP
发一个自己用JS写的实用看图工具实现代码
2008/07/26 Javascript
游览器中javascript的执行过程(图文)
2012/05/20 Javascript
JavaScript获取table中某一列的值的方法
2014/05/06 Javascript
jQuery实现购物车多物品数量的加减+总价计算
2014/06/06 Javascript
AngularJS过滤器filter用法分析
2016/12/11 Javascript
Node.js对MongoDB数据库实现模糊查询的方法
2017/05/03 Javascript
微信小程序实现鼠标拖动效果示例
2017/12/01 Javascript
nodeJs的安装与npm全局环境变量的配置详解
2020/01/06 NodeJs
es6数组之扩展运算符操作实例分析
2020/04/25 Javascript
python关键字and和or用法实例
2015/05/28 Python
python中pandas.DataFrame对行与列求和及添加新行与列示例
2017/03/12 Python
Tensorflow 利用tf.contrib.learn建立输入函数的方法
2018/02/08 Python
python实现将excel文件转化成CSV格式
2018/03/22 Python
Python实现base64编码的图片保存到本地功能示例
2018/06/22 Python
python调用摄像头拍摄数据集
2019/06/01 Python
Python爬虫:url中带字典列表参数的编码转换方法
2019/08/21 Python
django2.2安装错误最全的解决方案(小结)
2019/09/24 Python
YUV转为jpg图像的实现
2019/12/09 Python
Python 如何定义匿名或内联函数
2020/08/01 Python
压铸汽车模型收藏家:Diecastmodelswholesale.com
2016/12/21 全球购物
北美领先的智能产品购物网站:Wellbots
2018/06/11 全球购物
莱德杯高尔夫欧洲官方商店:Ryder Cup Shop
2019/08/14 全球购物
开发中都用到了那些设计模式?用在什么场合?
2014/08/21 面试题
机械设计专业应届生求职信
2013/11/21 职场文书
管理学院毕业生自荐信范文
2014/03/10 职场文书
领导干部群众路线对照检查材料
2014/11/05 职场文书
违反工作规定检讨书范文
2014/12/14 职场文书
婚礼新人答谢词
2015/01/04 职场文书
2015年秋季运动会加油稿
2015/07/22 职场文书
2019年二手房买卖合同范本
2019/10/14 职场文书
《攀登者》:“海拔8000米以上,你不能指望任何人”
2019/11/25 职场文书
Html5新增了哪些功能
2021/04/16 HTML / CSS
在CSS中使用when/else的方法
2022/01/18 HTML / CSS