PyQt5 界面显示无响应的实现


Posted in Python onMarch 26, 2020

在GUI程序中,主线程也叫GUI线程,因为它是唯一被允许执行GUI相关操作的线程。对于一些耗时的操作,如果放在主线程中,就是出现界面无法响应的问题。

界面假死分析

在编写QT的界面程序时,当我们调用QApplication.exec()时,我们就启动了QT的事件循环。在开始的时候,QT会发出一些事件来显示和绘制窗口部件。在这之后,事件循环就开始运行,不断地检查是不是有事件发生并且把这些事件发送给应用程序中的QObject。

当一个事件被处理时,其他事件也可能会产生并且追加到QT的事件队列中。如果我们在处理一个特定的事件上耗费过多的时间,用户界面就会变得不能够响应。例如在OCS保存一个观测流程的过程中,一直到文件保存完毕,窗口系统产生的一些事件才会被处
理。在保存过程中,这个应用程序就不能响应窗口系统的请求来重绘自己。

解决方法

  • 方式一使用多线程:一个处理应用程序用户界面的线程,另外一个执行文件保存的线程。
  • 方法二:调用QApplication.processEvents()

博主推荐使用第二种方法,该方法是在事件处理程序中调用QApplication.processEvents()。

这个函数告诉QT处理来处理任何没有被处理的事件,并且将控制权返回给调用者。实际上,QApplication.exec()就是一个不停调用QApplication.processEvents()函数的小while循环。这种方式的危险性在于,也许用户在观测流程未保存好之前就关闭了主窗口,或者在界面上通过鼠标或键盘执行了其它的输入,以至于观测流程未保存好就企图被程序使用。对于这个问题的解决办法是把 qApp -> processEvents(); 替换为 qApp -> eventLoop() -> processEvents( QEventLoop::ExcludeUserInput ); 通过这个调用告诉QT忽略鼠标和键盘事件。

...
  def downfile(self,file, url):
  print("开始下载:", file, url)
  try:
   r = requests.get(url, stream=True)
   with open(file, 'wb') as fd:
    for chunk in r.iter_content():
     fd.write(chunk)
     QApplication.processEvents()
  except Exception as e:
   print("下载失败了", e)
 ...

------------------------------------------补充一下方法一--------------------------》》》》》

说实话快有大半年没怎么使用过python了,关于多线程的处理方式,解释可能不是那么清楚。(目前是一个phper,上半年基本是补PHP方面的基础知识,也就是够用还不精通的一个状态)

先上一个半年前的小作品,是关于微信公众号方面的一些。

PyQt5 界面显示无响应的实现

这里就不谈用途与使用方法了,大概的讲一下,遇到界面假死的处理方法之一。话不多说,先上代码

from PyQt5.QtCore import QThread, pyqtSignal
 
class interface(QMainWindow, Ui_MainWindow):
 """
 Class documentation goes here.
 """
 def xxxx():
  "此处省略无数行代码......"
  self.Work()
 
 def Work(self):
  self.thread = RunThread()
  self.thread.start()
 
class RunThread(QThread):
 # python3,pyqt5与之前的版本有些不一样
 # 通过类成员对象定义信号对象
 # _signal = pyqtSignal(str)
 
 trigger = pyqtSignal()
 
 def __init__(self, parent=None):
  super(RunThread, self).__init__()
 
 def __del__(self):
  self.wait()
 
 def run(self):
  # 处理你要做的业务逻辑,这里是通过一个回调来处理数据,这里的逻辑处理写自己的方法
  dlg.Config['user'] = dlg.check_account['account']
  dlg.Config['passwd'] = dlg.check_account['password']
  dlg.Config['jk'] = 'http://xxx.com'
  if dlg.num != 1:
   dlg.operato.config_item(dlg.Config, dlg.wx_update) # 初始化配置
  else:
   dlg.operato.config_item(dlg.Config, dlg.wx_create) # 初始化配置
 
  self.trigger.emit()

说实话还是蛮喜欢python的这种简洁的写法的,所以在很长的一段时间里,一直是比较注重代码的简洁度与良好的注释。em...,不过在其它语言中很难保持这种初心,现在是比较注重性能,响应时间,并发、安全等问题。

这里的interface是主窗口类,如果想在自己的窗口中实现,加一个RunThread类,并在主窗口中定义一个函数,用于调用Work类方法就可以了。通过代码可以看到,不到50行的代码就实现了方法一中的功能了。pyqt5有很多自己的方法,包括多线程等等。这里提供的是一种思路。当然还有很多种方式实现,大家可以去探索一下,好的方法可以一起分享讨论。

========================================7月24号更新=================================

先放一个效果图,

PyQt5 界面显示无响应的实现

正常情况下会将一些耗时函数扔进Qthread线程中来避免页面假死的情况。

但并不是所有的都是行的通的,

PyQt5 界面显示无响应的实现

当使用异步协程的时候,pyqt5推荐的是使用quamash

import sys
import asyncio
import time
 
from PyQt5.QtWidgets import QApplication, QProgressBar
from quamash import QEventLoop, QThreadExecutor
 
app = QApplication(sys.argv)
loop = QEventLoop(app)
asyncio.set_event_loop(loop) # NEW must set the event loop
 
progress = QProgressBar()
progress.setRange(0, 99)
progress.show()
 
async def master():
 await first_50()
 with QThreadExecutor(1) as exec:
  await loop.run_in_executor(exec, last_50)
 # TODO announce completion?
 
async def first_50():
 for i in range(50):
  progress.setValue(i)
  await asyncio.sleep(.1)
 
def last_50():
 for i in range(50,100):
  loop.call_soon_threadsafe(progress.setValue, i)
  time.sleep(.1)
 
with loop: ## context manager calls .close() when loop completes, and releases all resources
 loop.run_until_complete(master())

还有一种情况,就是在UI主线程中执行,需要注意的是,如果是耗时任务则会造成界面的卡死,并不大友好。

到此这篇关于PyQt5 界面显示无响应的实现的文章就介绍到这了,更多相关PyQt5 界面显示无响应内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
使用python BeautifulSoup库抓取58手机维修信息
Nov 21 Python
Python2.7 实现引入自己写的类方法
Apr 29 Python
python跳过第一行快速读取文件内容的实例
Jul 12 Python
python: 自动安装缺失库文件的方法
Oct 22 Python
使用TensorFlow实现二分类的方法示例
Feb 05 Python
Python multiprocessing多进程原理与应用示例
Feb 28 Python
一篇文章彻底搞懂Python中可迭代(Iterable)、迭代器(Iterator)与生成器(Generator)的概念
May 13 Python
python matplotlib实现将图例放在图外
Apr 17 Python
python Tornado框架的使用示例
Oct 19 Python
python自动化之如何利用allure生成测试报告
May 02 Python
OpenCV3.3+Python3.6实现图片高斯模糊
May 18 Python
Python+腾讯云服务器实现每日自动健康打卡
Dec 06 Python
Python基于class()实现面向对象原理详解
Mar 26 #Python
Python文件读写w+和r+区别解析
Mar 26 #Python
Python装饰器实现方法及应用场景详解
Mar 26 #Python
pycharm中导入模块错误时提示Try to run this command from the system terminal
Mar 26 #Python
Python多进程编程常用方法解析
Mar 26 #Python
简单了解python调用其他脚本方法实例
Mar 26 #Python
Python tornado上传文件的功能
Mar 26 #Python
You might like
PHP中动态显示签名和ip原理
2007/03/28 PHP
PHP中比较时间大小实例
2014/08/21 PHP
php选择排序法实现数组排序实例分析
2015/02/16 PHP
PHP的pcntl多进程用法实例
2015/03/19 PHP
PHP微信开发之有道翻译
2016/06/23 PHP
laravel 5.3中自定义加密服务的方案详解
2017/05/09 PHP
悬浮数字的实现案例
2014/02/19 Javascript
使用Javascript简单实现图片无缝滚动
2014/12/05 Javascript
js与jquery回车提交的方法
2015/02/03 Javascript
Bootstrap Chart组件使用教程
2016/04/28 Javascript
Vue.js表单控件实践
2016/10/27 Javascript
javascript基础练习之翻转字符串与回文
2017/02/20 Javascript
Angularjs实现控制器之间通信方式实例总结
2018/03/27 Javascript
Vue中的无限加载vue-infinite-loading的方法
2018/04/08 Javascript
layerUI下的绑定事件实例代码
2018/08/17 Javascript
JavaScript实现简单日历效果
2020/09/11 Javascript
微信小程序实现日历小功能
2020/11/18 Javascript
[43:24]VG vs Serenity 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/20 DOTA
Python使用xlrd模块操作Excel数据导入的方法
2015/05/26 Python
Python matplotlib绘图可视化知识点整理(小结)
2018/03/16 Python
基于wxPython的GUI实现输入对话框(2)
2019/02/27 Python
Python的Tkinter点击按钮触发事件的例子
2019/07/19 Python
python脚本实现音频m4a格式转成MP3格式的实例代码
2019/10/09 Python
python对Excel的读取的示例代码
2020/02/14 Python
使用python 计算百分位数实现数据分箱代码
2020/03/03 Python
python实现人像动漫化的示例代码
2020/05/17 Python
使用Dajngo 通过代码添加xadmin用户和权限(组)
2020/07/03 Python
matplotlib教程——强大的python作图工具库
2020/10/15 Python
详解css3 mask遮罩实现一些特效
2018/10/24 HTML / CSS
谷歌浏览器小字体处理方案即12px以下字体
2013/12/17 HTML / CSS
计算机大学生的自我评价
2013/10/15 职场文书
电信专业毕业生推荐信
2013/11/18 职场文书
有趣的广告词
2014/03/18 职场文书
党员批评与自我批评发言材料
2014/10/14 职场文书
夫妻分居协议书范本
2014/11/28 职场文书
2016年国陪研修感言
2015/11/18 职场文书