先说遇到的问题希望遇到和我一样问题的童鞋也可以成功解决。我在处理逻辑业务时候比较耗时经常造成界面未响应!!!。

但是当使用python 的thread时候会造成主界面数据复原,暂时不知道什么原因。之后开始我的学习之路。

因为qt界面的刷新相当于一直while,当有耗时多的任务时就会造成阻塞无法完成刷新,造成界面未响应。

这时候就需要使用Qthread处理业务逻辑,主线程继续处理界面。分离ui界面与业务逻辑。

要使用QThread开始一个线程,可以创建它的一个子类,然后覆盖其QThread.run()函数

class Thread(QThread):

def __init__(self):

super().__init__()

def run(self):

# 线程相关代码

pass

# 创建一个新的线程

thread = Thread()

thread.start()

在使用线程时可以直接得到Thread实例,调用其start()函数即可启动线程,线程启动后,会调用其实现的run方法,该方法就是线程的执行函数,当run()退出之后线程基本就结束了。

QThread类中的常用方法:

start() 启动线程

wait() 阻止线程

sleep(s) 强制当前线程睡眠s秒

QThread类中的常用信号:

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

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

当在窗口中显示的数据比较简单时,可以把读取数据的业务逻辑放在窗口的初始化代码中;但如果读取数据的时间比较长,比如网络请求数据的时间比较长,则可以把这部分逻辑放在QThread线程中,实现界面的数据显示和数据读取的分离.

from PyQt5.QtCore import *

from PyQt5.QtWidgets import *

import sys

class Worker(QThread):

sinOut = pyqtSignal(str) # 自定义信号,执行run()函数时,从相关线程发射此信号

def __init__(self, parent=None):

super(Worker, self).__init__(parent)

self.working = True

self.num = 0

def __del__(self):

self.working = False

self.wait()

def run(self):

while self.working == True:

file_str = 'File index {0}'.format(self.num) # str.format()

self.num += 1

# 发出信号

self.sinOut.emit(file_str)

# 线程休眠2秒

self.sleep(2)

class MainWidget(QWidget):

def __init__(self, parent=None):

super(MainWidget, self).__init__(parent)

self.setWindowTitle("QThread 例子")

# 布局管理

self.listFile = QListWidget()

self.btnStart = QPushButton('开始')

layout = QGridLayout(self)

layout.addWidget(self.listFile, 0, 0, 1, 2)

layout.addWidget(self.btnStart, 1, 1)

# 连接开始按钮和槽函数

self.btnStart.clicked.connect(self.slotStart)

# 创建新线程,将自定义信号sinOut连接到slotAdd()槽函数

self.thread = Worker()

self.thread.sinOut.connect(self.slotAdd)

# 开始按钮按下后使其不可用,启动线程

def slotStart(self):

self.btnStart.setEnabled(False)

self.thread.start()

# 在列表控件中动态添加字符串条目

def slotAdd(self, file_inf):

self.listFile.addItem(file_inf)

if __name__ == "__main__":

app = QApplication(sys.argv)

demo = MainWidget()

demo.show()

sys.exit(app.exec_())

这个经典例子,虽然解决了界面的数据显示和数据读取的分离,但是如果数据的读取非常消耗时间,则会造成界面卡死,下面是一个需要耗费很长时间读取数据的例子。

import sys from PyQt5.QtCore

import * from PyQt5.QtGui

import * from PyQt5.QtWidgets

import * global sec sec = 0

def setTime():

global sec sec += 1

# LED显示数字+1

lcdNumber.display(sec)

def work():

#每秒计数

timer.start(1000)

# 开始一次非常耗时的计算

# 这里用一个2 000 000 000次的循环来模拟

for i in range(200000000):

pass timer.stop()

if __name__ == "__main__":

app = QApplication(sys.argv)

top = QWidget() top.resize(300, 120)

# 垂直布局类

QVBoxLayout layout = QVBoxLayout(top)

# 添加控件

lcdNumber = QLCDNumber()

layout.addWidget(lcdNumber)

button = QPushButton("测试")

layout.addWidget(button)

timer = QTimer()

# 每次计时结束,触发setTime

timer.timeout.connect(setTime)

# 连接测试按钮和槽函数

work button.clicked.connect(work)

top.show()

sys.exit(app.exec_())

程序的运行逻辑如下:

这里写图片描述

正常情况下,在点击按钮之后,LCD上的数字会随着时间发生变化,但是在实际运行过程中会发现点击按钮之后,程序界面直接停止响应,直到循环结束才开始重新更新,于是计时器始终显示为0。

在上面这个程序中没有引入新的线程,PyQt中所有的窗口都在UI主线程中(就是执行了QApplication.exec()的线程),在这个线程中执行耗时的操作会阻塞UI线程,从而让窗口停止响应。

为了避免出现上述问题,要使用QThread开启一个新的线程,在这个线程中完成耗时的操作:

mport sys

from PyQt5.QtCore import *

from PyQt5.QtGui import *

from PyQt5.QtWidgets import *

global sec

sec = 0

# 增加了一个继承自QThread类的类,重新写了它的run()函数

# run()函数即是新线程需要执行的:执行一个循环;发送计算完成的信号。

class WorkThread(QThread):

trigger = pyqtSignal()

def __int__(self):

super(WorkThread, self).__init__()

def run(self):

for i in range(2000000000):

pass

# 循环完毕后发出信号

self.trigger.emit()

def countTime():

global sec

sec += 1

# LED显示数字+1

lcdNumber.display(sec)

def work():

# 计时器每秒计数

timer.start(1000)

# 计时开始

workThread.start()

# 当获得循环完毕的信号时,停止计数

workThread.trigger.connect(timeStop)

def timeStop():

timer.stop()

print("运行结束用时", lcdNumber.value())

global sec

sec = 0

if __name__ == "__main__":

app = QApplication(sys.argv)

top = QWidget()

top.resize(300, 120)

# 垂直布局类QVBoxLayout

layout = QVBoxLayout(top)

# 加个显示屏

lcdNumber = QLCDNumber()

layout.addWidget(lcdNumber)

button = QPushButton("测试")

layout.addWidget(button)

timer = QTimer()

workThread = WorkThread()

button.clicked.connect(work)

# 每次计时结束,触发 countTime

timer.timeout.connect(countTime)

top.show()

sys.exit(app.exec_())

程序运行逻辑简单说明:

按下按钮后,计时器开始计数,并启动一个新的线程,在这个线程里,执行一个循环并在循环结束时发送完成信号,在完成信号发出后,执行与之相关联的槽函数,关闭定时器。

再次运行程序,界面有了响应。

事件处理

对于执行很耗时的程序来说,由于PyQt需要等待程序执行完毕才能进行下一步,这个过程表现在界面上就是卡顿;而如果在执行这个耗时程序时不断地运行QApplication.processEvents(),那么就可以实现一边执行耗时程序,一边刷新页面的功能,会给人一种相对更流畅的感觉,QApplication.processEvents()的使用方法是,在主函数执行耗时操作的地方,加入QApplication.processEvents(),processEvents()函数的使用方法简单来说就是刷新页面。(可以在table获取数据及时显示等操作使用)

from PyQt5.QtWidgets import QWidget, QPushButton, QApplication, QListWidget, QGridLayout

import sys

import time

class WinForm(QWidget):

def __init__(self, parent=None):

super(WinForm, self).__init__(parent)

self.setWindowTitle("实时刷新界面例子")

self.listFile = QListWidget()

self.btnStart = QPushButton('开始')

layout = QGridLayout(self)

layout.addWidget(self.listFile, 0, 0, 1, 2)

layout.addWidget(self.btnStart, 1, 1)

self.setLayout(layout)

self.btnStart.clicked.connect(self.slotAdd)

def slotAdd(self):

for n in range(10):

str_n = 'File index {0}'.format(n)

self.listFile.addItem(str_n)

QApplication.processEvents()

time.sleep(1)

if __name__ == "__main__":

app = QApplication(sys.argv)

form = WinForm()

form.show()

sys.exit(app.exec_())

如果不添加QApplication.processEvents(),会在卡顿之后全部结果,添加之后,也不能保证每个都是逐行显示,只是比不加相对流畅一点,效果是不如多线程的。

总结

能用多线程尽量用多线程,不论数据处理还是界面流程性都优于QApplication.processEvents(),但是当数据量小的时候可以使用QApplication.processEvents(),代码比较简单。

Java业务逻辑pyqt_PyQt5 UI界面与业务逻辑分离相关推荐

  1. Java串口助手 带UI界面 Java串口调试工具 FPV

    Java串口助手 带UI界面 Java串口调试工具 FPV 效果图 随便讲点 依赖jar包 代码 测试用代码 效果图 随便讲点 这个说是串口调试工具有点尴尬, 因为最开始是为了用电脑在自己做的小车上玩 ...

  2. 移动护理、护士工作站 UI界面及业务

    之前做的移动护理界面,发出现大家参考一下 用的是C# MVC做为服务端,UniAPP 开发的H5做为PAD端 这是PC端 的界面 这是PAD端的界面

  3. AndroidStudio中使用XML和Java代码混合控制UI界面实现QQ相册照片列表页面

    场景 效果 注: 博客: https://blog.csdn.net/badao_liumang_qizhi 关注公众号 霸道的程序猿 获取编程相关电子书.教程推送与免费下载. 实现 新建Androi ...

  4. 在Service中通过WindowManger添加View的方式来把UI界面显示出来

    整体方案 在Service中通过WindowManger添加View的方式来把UI界面显示出来 业务场景 具体场景 IQOO手机,游戏辅助 这种场景能否使用Activity方式来做 使用activit ...

  5. Android(五)——控制UI界面的方法

    文章目录 1. 使用XML布局文件控制UI界面(推荐) 2. 在Java代码中控制UI界面 3. 使用XML和Java代码混合控制UI界面 4. 开发自定义的View 1. 使用XML布局文件控制UI ...

  6. 用户界面设计之关于控制UI界面的简单总结

    用户界面设计是Android应用开发的一项重要内容.Android提供了四种控制UI界面的方法,分别为: 1.使用XML布局文件控制UI界面 2.在代码中控制UI界面 3.使用XML和Java代码混合 ...

  7. react获取id_解决React应用界面开发常见痛点(一)业务逻辑与UI分离

    前言:本系列是针对于React在界面开发痛点的一些解决方案,只是React应用中偏向展示的一环 构建一个业务与UI分离的react应用 本篇是基于HOC方案并未使用Hooks 业务逻辑与UI 在编写一 ...

  8. python3可视化窗口操作_Python3.x+PyQtChart实现数据可视化界面(PyQtChart绘图;还有保存图片)和业务逻辑分离案例01_自己写的,有UI界面源代码...

    [实例简介] Python3.x+PyQtChart实现数据可视化界面(PyQtChart绘图:还有保存图片)和业务逻辑分离案例01_自己写的,有UI界面源代码. [实例截图] [核心代码] wang ...

  9. 表现层(UI)、业务逻辑层(BLL)、数据访问层(DAL)

    三层架构(3-tier application) 通常意义上的三层架构就是将整个业务应用划分为:表现层(UI).业务逻辑层(BLL).数据访问层(DAL).区分层次的目的即为了"高内聚,低耦 ...

最新文章

  1. Blender 2.9中的真实感三维产品全流程制作学习教程
  2. 康乐主机系统怎么安装php,Kangle EP面板详细安装说明
  3. Linux之hugepage大页内存理论
  4. Linux系统启动过程分析 -转
  5. 反恐精英online单机版有各种武器
  6. 激励机制中的经济学和博弈论模型(2)
  7. 【软技能】完全写作指南--演讲幻灯片
  8. 前端实现3D魔方旋转特效
  9. c语言abs和fabs的区别是什么?
  10. MES生产管理系统中,看板管理究竟是什么
  11. **Unity环境光遮蔽(Ambient Occlusion)Shader实现逻辑**
  12. go中使用protobuf
  13. android+动态隐藏图标,2018安卓手机怎么隐藏图标 进入隐藏应用界面
  14. Bad Request This combination of host and port requires TLS. postman
  15. linux内部网关协议igp,在自治系统内部的各个路由器之间,运行的是内部网关协议IGP。早期的IGP叫做【11】 ,它执行 【12】 。_考题宝...
  16. Microsoft Project
  17. 18个配色(色彩搭配)资源网站——设计师福利
  18. 为设计指定输入端口驱动强度:set_driving_cell、set_drive 和set_input_transition
  19. BLOCK层代码分析(10)IO下发之IO下发函数总结
  20. python利用PyQt5和QTDesginer开发GUI应用(二)、股票查询工具

热门文章

  1. Java基础--通过反射获取私有的成员方法示例代码
  2. python退出循环快捷_python退出循环的方法
  3. Qt工程文件Pro中判断Qt版本号
  4. 强化学习7——基于环境模型的RL方法
  5. 二分查找(循序渐进由0到1掌握二分)
  6. kiss原则包括什么_和女孩牵手与kiss的具体方法
  7. 常用算法 之一 详解 MD5 实现(基于算法的官方原文档)及源码详细注释
  8. 数据结构(字典,跳跃表)、使用场景(计数器、缓存、查找表、消息队列、会话缓存、分布式锁)、Redis 与 Memcached、 键的过期时间、数据淘汰策略、持久化(RDB、AOF)
  9. 计算机丢失wininet,win7系统启动程序提示因为计算机中丢失wininet.dll的解决方法...
  10. linux脚本实现复制,Shell脚本实现复制文件到多台服务器的代码分享