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字符串str和字节数组相互转化方法
Mar 18 Python
对命令行模式与python交互模式介绍
May 12 Python
Python3中内置类型bytes和str用法及byte和string之间各种编码转换 问题
Sep 27 Python
Python中浅拷贝copy与深拷贝deepcopy的简单理解
Oct 26 Python
Python实现html转换为pdf报告(生成pdf报告)功能示例
May 04 Python
Flask框架路由和视图用法实例分析
Nov 07 Python
Python pexpect模块及shell脚本except原理解析
Aug 03 Python
Python使用lambda抛出异常实现方法解析
Aug 20 Python
Python request中文乱码问题解决方案
Sep 17 Python
PyCharm最新激活码PyCharm2020.2.3有效
Nov 18 Python
python process模块的使用简介
May 14 Python
Django drf请求模块源码解析
Jun 08 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
PHP初学者常见问题集合 修正版(21问答)
2010/03/23 PHP
php数组函数序列之array_push() 数组尾部添加一个或多个元素(入栈),返回新长度。
2011/11/07 PHP
PHP树的深度编历生成迷宫及A*自动寻路算法实例分析
2015/03/10 PHP
Laravel 5框架学习之模型、控制器、视图基础流程
2015/04/08 PHP
Yii中srbac权限扩展模块工作原理与用法分析
2016/07/14 PHP
Yii 2中的load()和save()示例详解
2017/08/03 PHP
PHP xpath()函数讲解
2019/02/11 PHP
javascript 对象比较实现代码
2009/04/27 Javascript
Javascript 加载和执行-性能提高篇
2012/12/28 Javascript
jQuery设置和获取HTML、文本和值示例
2014/07/08 Javascript
javascript实现的简单的表单验证
2015/07/10 Javascript
jQuery实现点击查看大图并以弹框的形式居中
2016/08/08 Javascript
JavaScript使用原型和原型链实现对象继承的方法详解
2017/04/05 Javascript
详解NODEJS的http实现
2018/01/04 NodeJs
如何在sae中设置django,让sae的工作环境跟本地python环境一致
2017/11/21 Python
python中的内置函数max()和min()及mas()函数的高级用法
2018/03/29 Python
python logging日志模块以及多进程日志详解
2018/04/18 Python
python3+PyQt5+Qt Designer实现堆叠窗口部件
2018/04/20 Python
python+openCV利用摄像头实现人员活动检测
2019/06/22 Python
如何使用Python实现自动化水军评论
2019/06/26 Python
详解Python IO口多路复用
2020/06/17 Python
python 动态绘制爱心的示例
2020/09/27 Python
解决pycharm导入numpy包的和使用时报错:RuntimeError: The current Numpy installation (‘D:\\python3.6\\lib\\site-packa的问题
2020/12/08 Python
使用iframe+postMessage实现页面跨域通信的示例代码
2020/01/14 HTML / CSS
Bobbi Brown芭比波朗美国官网:化妆师专业彩妆保养品品牌
2016/08/18 全球购物
linux系统都有哪些运行级别
2016/03/26 面试题
美德好少年主要事迹
2014/01/29 职场文书
老公保证书范文
2014/04/29 职场文书
基层党员群众路线教育实践活动个人对照检查材料思想汇报
2014/10/05 职场文书
购房协议书范本(无房产证)
2014/10/07 职场文书
升学宴学生答谢词
2015/01/05 职场文书
毕业生自我鉴定范文
2019/05/13 职场文书
宪法宣传标语100条
2019/10/15 职场文书
八年级作文之友情
2019/11/25 职场文书
关于html选择框创建占位符的问题
2021/06/09 HTML / CSS
zabbix如何添加监控主机和自定义监控项
2022/08/14 Servers