PyQt5 界面显示无响应的实现

在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 界面显示无响应内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2020-03-26

pyqt5使用按钮进行界面的跳转方法

简介 进行按钮进行界面的跳转,我这里面我介绍两种,一种是没有使用Qtdesigner的代码,另一种是使用Qtdesigner的代码 代码1 import sys from PyQt5.QtWidgets import QMainWindow, QPushButton, QApplication class First(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): self.

pyqt5实现登录界面的模板

本文实例为大家分享了pyqt5登录界面的实现模板,供大家参考,具体内容如下 说明 本例,展示了通过登录界面打开主界面的实现方式. 其中,登录的账号与密码判断都比较简单,请大家根据自己需要,自行完善补充. [如下代码,完全复制,直接运行,即可使用] import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import * ################################

python GUI库图形界面开发之PyQt5浏览器控件QWebEngineView详细使用方法

PyQt5浏览器控件QWebEngineView PyQt5使用QWebEngineView控件来展示HTML页面,对老版本的QWebView类不在进行维护,因为QWebEngineView使用CHromium内核可以给用户带来更好的体验 QWebEngineView类中常用方法 方法 描述 load(QUrl url) 加载指定的URL并显示 setHtml(QString&html) 将网页视图的内容设置为指定的HTML内容 QWebEngineView控件使用load()函数加载一个Web

python GUI库图形界面开发之PyQt5表格控件QTableView详细使用方法与实例

PyQt5表格控件QTableView简介 在通常情况下,一个应用需要和一批数据进行交互,然后以表格的形式输出这些信息,这时就需要用到QTableView类了,在QTableView中可以使用自定义的数据模型来显示内容,通过setModel来绑定数据源 QTableWidget继承自QTableView,主要区别是QTableView可以使用自定义的数据模型来显示内容(先通setModel来绑定数据源),而QTableWidget自能使用标准的数据模型,并且其单元格数据是通过QTableWidg

python GUI库图形界面开发之PyQt5控件QTableWidget详细使用方法与属性

QTableWidget介绍 QTableWidget是Qt程序中常用的显示数据表格的控件,类似于c#中的DataGrid.QTableWidget是QTableView的子类,它使用标准的数据模型,并且其单元数据是通过QTableWidgetItem对象来实现的,使用QTableWidget时就需要QTableWidgetItem.用来表示表格中的一个单元格,整个表格就是用各个单元格构建起来的 QTableWidget类中的常用方法 方法 描述 setROwCount(int row) 设置Q

python GUI库图形界面开发之PyQt5下拉列表框控件QComboBox详细使用方法与实例

PyQt5下拉列表框控件QComboBox介绍 QComboBox是一个集按钮和下拉选项于一体的控件,也称做下拉列表框 QComboBox类中的常用方法如表 方法 描述 addItem() 添加一个下拉选项 addItems() 从列表中添加下拉选项 Clear() 删除下拉选项集合中的所有选项 count() 返回下拉选项集合中的数目 currentText() 返回选中选项的文本 itemText(i) 获取索引为i的item的选项文本 currentIndex() 返回选中项的索引 set

python GUI库图形界面开发之PyQt5树形结构控件QTreeWidget详细使用方法与实例

PyQt5树形结构控件QTreeWidget简介 QTreeWidget 类根据预设的模型提供树形显示控件. QTreeWidget 使用类似于 QListView 类的方式提供一种典型的基于 item 的树形交互方法类,该类基于QT的"模型/视图"结构,提供了默认的模型来支撑 item 的显示,这些 item 类为 QTreeWidgetItem 类. 如果不需要灵活的"模型/视图"框架,可以使用QTreeWidget 来创建有层级关系的树形结构.当把标准 ite

pyqt5利用pyqtDesigner实现登录界面

本文实例为大家分享了pyqt5利用pyqtDesigner实现登录界面的具体代码,供大家参考,具体内容如下 为便于操作 界面和逻辑分离 逻辑类: import sys import pymysql from loginUI import * //导入 from PyQt5.QtWidgets import * from PyQt5 import QtWidgets, QtCore, QtGui from PyQt5.QtCore import * from PyQt5.QtGui import

pyQt5实时刷新界面的示例

如下所示: from PyQt5.QtCore import QThread , pyqtSignal, QDateTime , QObject from PyQt5.QtWidgets import QApplication, QDialog, QLineEdit import time import sys class BackendThread(QObject): # 通过类成员对象定义信号 update_date = pyqtSignal(str) # 处理业务逻辑 def run(se

AngularJs实现聊天列表实时刷新功能

昨天在做app的聊天列表时,遇到了一个问题,消息监听器监听到了一个新的消息,但是如果这时已经处于消息列表的页面那么消息列表并不会及时更新. 我的想法是在service层中的监听器方法里,当监听到了一个新的消息,那么就在根作用域中发出一个广播,告诉controller层需要去获取最新的消息列表了. service层中发出广播: controller层中接听广播: rootScope是所有scope的父级 它的广播(broadcast)和监听(on) 可以在无交集的controller间使用 sco

关于JavaScript跨域问题及实时刷新解决方案

在自己页面显示其他网站上面的数据,需要用Ajax,就涉及到跨域问题, 解决方案:jQuery.support.cors = true; (浏览器支持跨域访问), 实例: 复制代码 代码如下: //浏览器支持跨域访问 jQuery.support.cors = true; $.ajax({ url: "http://www.rj99999.com/Price/ListPrice.html", dataType: 'html', success: function (data, textS

基于Vue实现tab栏切换内容不断实时刷新数据功能

先说一下产品需求,就是有几个tab栏,每个tab栏对应的ajax请求不一样,内容区域一样,内容为实时刷新数据,每3s需要重新请求,返回的数据在内容区域展示,每点击一次tab栏需停止其他tab栏ajax请求,防止阻塞,首次加载页面的时候又不能5个ajax同时请求,只需要请求第一个就好 也没有必要建立5个区域,控制显示隐藏,浪费性能,业务代码就不贴了,把大概原理的代码贴上来 先是用jq实现了一版 <!DOCTYPE html> <html lang="en"> &l

基于d3.js实现实时刷新的折线图

先来看看效果图 下面直接上源代码,html文件 <html> <head> <meta charset="utf-8"> <title>实时刷新折线图</title> <style> .axis path, .axis line{ fill: none; stroke: black; shape-rendering: crispEdges; } .axis text { font-family: sans-seri

php+ajax实时刷新简单实例

本文实例讲述了php+ajax实时刷新简单实现方法,分享给大家供大家参考.具体如下: ajax自动刷新好像是个很常见的问题,之前做一个网页聊天室程序也是卡在了这上面,经过了这段时间的学习,终于做出了一个可以自动刷新网页的代码框架,希望正在迷茫的亲们不要像我一样走了这么多弯路 废话不多说 上代码: html部分: <html> <head> <script type="text/javascript"> function loadXMLDoc()//a

js调用刷新界面的几种方式

有的时候需要手动调用来刷新界面,比如非动态切换的语言模式啊,风格样式啊什么的. <!DOCTYPE html> <html> <head> <meta charset='utf-8'> </head> <body> <button onclick="click1()">location.reload();</button> <button onclick="click2()&

js实现股票实时刷新数据案例

近来学习炒股,免不了上班时间看盘,总不能光明正大的用电脑看行情,一直盯着手机影响也不好,容易引起"关注". 所以就想自己做一个网页来达到看盘的目的,一个只显示几个关键数字的网页肯定不会引起怀疑.有想法了,就开始实现吧. 准备工作: 1.数据来源 2.网页数据显示 先帖出来源码,后面讲解 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/T

zTree实现节点修改的实时刷新功能

一.应用场景 在实际应用中会遇到动态操作树各节点的需求,在增加树节点后如何实时动态刷新树就十分有必要了. 二.项目实践 比如要在test1234节点下新建子节点,首先要选中test1234节点,添加成功后,根据test1234结点的TID去后台请求对应子节点数据,实现动态刷新.删除节点类似. 三.代码实现 1.初始化时必须设置配置 <span style="font-size:14px;"> async:{ enable:true, url:"../admin/s

微信小程序下拉刷新界面的实现

微信小程序下拉刷新界面的实现 利用onPullDownRefresh函数设置下拉刷新功能 一.在app.json中,将window选项中的enablePullDownRefresh设为true "window":{ "enablePullDownRefresh":true } 或者在要刷新的界面的XXX.json中设置enablePullDownRefresh设为true { "enablePullDownRefresh": true } 二.利

Android中刷新界面的二种方法

Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用. Android界面刷新方法有两种,分别是利用Handler和利用postInvalidate()来实现在线程中刷新界面. 利用Handler刷新界面 实例化一个Handler对象,并重写handleMessage方法调用invalidate()实现界面刷新:而在线程中通过sendMessag