Java业务逻辑pyqt_PyQt5 UI界面与业务逻辑分离
先说遇到的问题希望遇到和我一样问题的童鞋也可以成功解决。我在处理逻辑业务时候比较耗时经常造成界面未响应!!!。
但是当使用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界面与业务逻辑分离相关推荐
- Java串口助手 带UI界面 Java串口调试工具 FPV
Java串口助手 带UI界面 Java串口调试工具 FPV 效果图 随便讲点 依赖jar包 代码 测试用代码 效果图 随便讲点 这个说是串口调试工具有点尴尬, 因为最开始是为了用电脑在自己做的小车上玩 ...
- 移动护理、护士工作站 UI界面及业务
之前做的移动护理界面,发出现大家参考一下 用的是C# MVC做为服务端,UniAPP 开发的H5做为PAD端 这是PC端 的界面 这是PAD端的界面
- AndroidStudio中使用XML和Java代码混合控制UI界面实现QQ相册照片列表页面
场景 效果 注: 博客: https://blog.csdn.net/badao_liumang_qizhi 关注公众号 霸道的程序猿 获取编程相关电子书.教程推送与免费下载. 实现 新建Androi ...
- 在Service中通过WindowManger添加View的方式来把UI界面显示出来
整体方案 在Service中通过WindowManger添加View的方式来把UI界面显示出来 业务场景 具体场景 IQOO手机,游戏辅助 这种场景能否使用Activity方式来做 使用activit ...
- Android(五)——控制UI界面的方法
文章目录 1. 使用XML布局文件控制UI界面(推荐) 2. 在Java代码中控制UI界面 3. 使用XML和Java代码混合控制UI界面 4. 开发自定义的View 1. 使用XML布局文件控制UI ...
- 用户界面设计之关于控制UI界面的简单总结
用户界面设计是Android应用开发的一项重要内容.Android提供了四种控制UI界面的方法,分别为: 1.使用XML布局文件控制UI界面 2.在代码中控制UI界面 3.使用XML和Java代码混合 ...
- react获取id_解决React应用界面开发常见痛点(一)业务逻辑与UI分离
前言:本系列是针对于React在界面开发痛点的一些解决方案,只是React应用中偏向展示的一环 构建一个业务与UI分离的react应用 本篇是基于HOC方案并未使用Hooks 业务逻辑与UI 在编写一 ...
- python3可视化窗口操作_Python3.x+PyQtChart实现数据可视化界面(PyQtChart绘图;还有保存图片)和业务逻辑分离案例01_自己写的,有UI界面源代码...
[实例简介] Python3.x+PyQtChart实现数据可视化界面(PyQtChart绘图:还有保存图片)和业务逻辑分离案例01_自己写的,有UI界面源代码. [实例截图] [核心代码] wang ...
- 表现层(UI)、业务逻辑层(BLL)、数据访问层(DAL)
三层架构(3-tier application) 通常意义上的三层架构就是将整个业务应用划分为:表现层(UI).业务逻辑层(BLL).数据访问层(DAL).区分层次的目的即为了"高内聚,低耦 ...
最新文章
- Blender 2.9中的真实感三维产品全流程制作学习教程
- 康乐主机系统怎么安装php,Kangle EP面板详细安装说明
- Linux之hugepage大页内存理论
- Linux系统启动过程分析 -转
- 反恐精英online单机版有各种武器
- 激励机制中的经济学和博弈论模型(2)
- 【软技能】完全写作指南--演讲幻灯片
- 前端实现3D魔方旋转特效
- c语言abs和fabs的区别是什么?
- MES生产管理系统中,看板管理究竟是什么
- **Unity环境光遮蔽(Ambient Occlusion)Shader实现逻辑**
- go中使用protobuf
- android+动态隐藏图标,2018安卓手机怎么隐藏图标 进入隐藏应用界面
- Bad Request This combination of host and port requires TLS. postman
- linux内部网关协议igp,在自治系统内部的各个路由器之间,运行的是内部网关协议IGP。早期的IGP叫做【11】 ,它执行 【12】 。_考题宝...
- Microsoft Project
- 18个配色(色彩搭配)资源网站——设计师福利
- 为设计指定输入端口驱动强度:set_driving_cell、set_drive 和set_input_transition
- BLOCK层代码分析(10)IO下发之IO下发函数总结
- python利用PyQt5和QTDesginer开发GUI应用(二)、股票查询工具
热门文章
- Java基础--通过反射获取私有的成员方法示例代码
- python退出循环快捷_python退出循环的方法
- Qt工程文件Pro中判断Qt版本号
- 强化学习7——基于环境模型的RL方法
- 二分查找(循序渐进由0到1掌握二分)
- kiss原则包括什么_和女孩牵手与kiss的具体方法
- 常用算法 之一 详解 MD5 实现(基于算法的官方原文档)及源码详细注释
- 数据结构(字典,跳跃表)、使用场景(计数器、缓存、查找表、消息队列、会话缓存、分布式锁)、Redis 与 Memcached、 键的过期时间、数据淘汰策略、持久化(RDB、AOF)
- 计算机丢失wininet,win7系统启动程序提示因为计算机中丢失wininet.dll的解决方法...
- linux脚本实现复制,Shell脚本实现复制文件到多台服务器的代码分享