PyQt5 界面显示无响应的实现
作者:zulien 发布时间:2021-09-05 08:59:11
在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方面的基础知识,也就是够用还不精通的一个状态)
先上一个半年前的小作品,是关于微信公众号方面的一些。
这里就不谈用途与使用方法了,大概的讲一下,遇到界面假死的处理方法之一。话不多说,先上代码
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号更新=================================
先放一个效果图,
正常情况下会将一些耗时函数扔进Qthread线程中来避免页面假死的情况。
但并不是所有的都是行的通的,
当使用异步协程的时候,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主线程中执行,需要注意的是,如果是耗时任务则会造成界面的卡死,并不大友好。
来源:https://blog.csdn.net/zulien/article/details/84990708


猜你喜欢
- 在进行matplotlib画图的时候,经常会出现这个的报错,虽然知道是因为没有对应的字体的原因,但是,将字体下载后放到目标路径下,仍然没有办
- 项目中要对短文本进行相似度估计,word2vec是一个很火的工具。本文就word2vec的训练以及加载进行了总结。word2vec的原理就不
- 今天写爬虫偶然想到了初学正则表达式时候,看过一篇文章非常不错。检索一下还真的找到了。re模块re.search经常用match = re.s
- Numpy中的数组整体处理赋值操作一直让我有点迷糊,很多时候理解的不深入。今天单独列写相关的知识点,进行总结一下。先看两个代码片小例子:例子
- 写入cookie实例! var u = "value=123"; document.cookie = u; 读取cook
- 如下所示:import turtlefor i in range(100,0,-5): # 从100到0循环递减每次减5turt
- # -*-coding:utf-8-*-import sys, os'''将当前进程fork为一个守护进程注意:如果
- 目录支持多种类型的过滤避免多个范围查询优化排序理解索引概念最简单的方式是通过一个案例来进行,以下就是这样的一个案例。假设我们需要设计一个在线
- 本文不涉及分类器、训练识别器等算法原理,仅包含对其应用(未来我也会写自己对机器学习算法原理的一些观点和了解)首先我们需要知道的是利用现有框架
- 以行的形式读出一个文件最简单的方式是使用文件对象的readline()、readlines()和xreadlines()方法。Python2
- 前言说起这个事情吧也相对来说比较尴尬,对于一个技术来说忘记密码然后找回密码都是相当简单的一个事情,但是在生产环境中没有保存记录只能是自己的失
- 导语hello everyone! I'm kimiko!Miss me???嘿!中秋结束了,开始正式营业给大家继续送福
- 一般常用的有两个方法:1、使用DataFrame.index = [newName],DataFrame.columns = [newNam
- 生活中我们经常会遇到一些加密算法,今天我们就聊聊这些加密算法的Python实现。部分常用的加密方法基本都有对应的Python库,基本不再需要
- 下面记录一下在本地 Windwos 环境用 vagrant 搭建的虚拟机(Homestaead)和生产环境阿里云 CentOS 系统安装 N
- 环境准备卸载mariadbrpm -qa | grep mariadbrpm -e --nodeps mariadb-libs-5.5.60
- 记住:这时候08安装的时候要自定义一个实例 比如:mysql2008(不能在使用默认实例了) sql server 2008 express
- 1.获得盘名os.path.splitdrive(path)import ospath="C:\\Users\\wuyanzu\\
- 我们经常见到很多网站留言系统的显示访客的IP地址都是隐藏了一部分,以达到隐蔽访客真实地理位置的功能。如:111.222.333.*,当然在系
- 视频观看视频Pygame模块之pygame.draw本文将主要介绍Pygame的draw模块,主要内容翻译自pygame的官方文档pygam