java业务逻辑pyqt-ag凯发k8国际
先说遇到的问题希望遇到和我一样问题的童鞋也可以成功解决。我在处理逻辑业务时候比较耗时经常造成界面未响应!!!。
但是当使用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(),代码比较简单。
总结
以上是ag凯发k8国际为你收集整理的java业务逻辑pyqt_pyqt5 ui界面与业务逻辑分离的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: java 泛型int_java 泛型
- 下一篇: mysql原生分页语句_mysql原生分