日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java业务逻辑pyqt_PyQt5 UI界面与业务逻辑分离

發布時間:2024/10/8 java 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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界面与业务逻辑分离的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。