使用PySide多線程處理圖形界面卡頓問題詳解
在了解pyside多線程之前,如果是初學(xué)者可以先去看看我的另一篇文章Python多線程threading模塊實(shí)例詳解,文中有對(duì)多線程的概念進(jìn)行詳細(xì)介紹,如果有相關(guān)基礎(chǔ)可直接跳過。
1.為什么要使用多線程
在制作圖形界面時(shí),只用一個(gè)線程很容易導(dǎo)致卡頓無響應(yīng),一旦主線程被阻塞,那么整個(gè)圖形界面都會(huì)無法繼續(xù)使用,為了解決這個(gè)問題,就得使用多線程。
多線程的主要目的就是把各種任務(wù)放在子線程里處理,這樣的話就可以保證主界面的流暢使用,尤其是需要我們?cè)谥鹘缑嫔洗蜷_多個(gè)子界面。
因此在學(xué)習(xí)Pyside/PyQt時(shí),多線程是必定是要學(xué)習(xí)了解的知識(shí)點(diǎn),我們廢話不多說,直接開始!
2.信號(hào)與槽
信號(hào)與槽是pyside/pyQt中的一個(gè)核心概念,學(xué)習(xí)使用pyside/pyQt進(jìn)行圖形化界面的繪制時(shí)必然會(huì)使用到,因此我們首先要簡略介紹一下,熟練掌握此處知識(shí)點(diǎn)的小伙伴可以直接跳過。
在理解信號(hào)與槽這個(gè)概念時(shí),我們不用把他想的太復(fù)雜了,只需要知道:信號(hào)的作用就是用于觸發(fā)槽函數(shù)。
我們?cè)谑褂靡粋€(gè)軟件例如網(wǎng)易云音樂時(shí),想要播放某首歌,那么點(diǎn)擊播放的按鈕,歌就開始唱,此時(shí)點(diǎn)擊這個(gè)動(dòng)作就是一個(gè)信號(hào),而歌播放這個(gè)過程就是一個(gè)函數(shù)。
在編寫界面時(shí)也是如此,我們想要把某個(gè)觸發(fā)的信號(hào)與某個(gè)函數(shù)連接在一起,就常常需要使用connect方法,標(biāo)準(zhǔn)的格式是:
對(duì)象.對(duì)象的方法信號(hào).connect(槽函數(shù))
如果我們點(diǎn)擊一個(gè)按鈕對(duì)象Mybutton時(shí)想要觸發(fā)一個(gè)Myfunction函數(shù),那么就寫為:
Mybutton.clicked.connect(Myfunction)
如果到此處仍無法理解沒有關(guān)系,我們繼續(xù)往下看。
3.結(jié)合實(shí)例理解
實(shí)例1-不使用多線程導(dǎo)致的問題
我們來看第一個(gè)實(shí)例,該實(shí)例想要實(shí)現(xiàn)的效果是:點(diǎn)擊圖形界面上的按鈕便開始計(jì)時(shí),總共計(jì)時(shí)10秒,首先來看不使用多線程的情況下發(fā)現(xiàn)的問題:
""" Pyside6# QThread多線程 實(shí)例1:體驗(yàn)不使用多線程的結(jié)果 """ from PySide6.QtCore import QThread, Slot, Signal from PySide6.QtWidgets import QWidget, QApplication, QPushButton, QVBoxLayout, QLabel, QTextEdit import time from time import sleep # 主界面,繼承QWidget類 class MyGUI(QWidget): def __init__(self): # 重寫構(gòu)造方法 super().__init__() self.setup() # 創(chuàng)建界面 self.bind() # 綁定函數(shù) def bind(self): self.button.clicked.connect(self.timer) # 將按鈕與開啟新線程的槽函數(shù)通過click信號(hào)相連 def setup(self): layout = QVBoxLayout() # 界面布局為垂直布局 self.setLayout(layout) # 設(shè)置layout布局 self.resize(300, 150) # 重新設(shè)置界面大小 self.label = QLabel("點(diǎn)擊按鈕開始計(jì)時(shí)") # 定義標(biāo)簽控件 self.button = QPushButton("Click!") # 定義按鈕控件 self.text_edit = QTextEdit() # 定義可編輯文本框控件 layout.addWidget(self.label) # 放置標(biāo)簽控件 layout.addWidget(self.button) # 放置按鈕控件 layout.addWidget(self.text_edit) # 放置文本框界面 def timer(self): # 定義一個(gè)10s的計(jì)時(shí)器 count = 0 while count < 10: time.sleep(1) self.text_edit.setText(f"{count}") # 將當(dāng)前數(shù)值反映到文本框 count += 1 if __name__ == '__main__': app = QApplication([]) # 定義一個(gè)應(yīng)用 window = MyGUI() # 定義一個(gè)界面 window.show() # 展示界面 app.exec() # 啟動(dòng)應(yīng)用
運(yùn)行代碼后,出現(xiàn)以下界面:
點(diǎn)擊按鈕,開始計(jì)時(shí):
但是可以發(fā)現(xiàn),事情沒有安裝我們預(yù)想的情況那樣進(jìn)行,界面直接卡住了,變成“未響應(yīng)”的狀態(tài)。為什么會(huì)產(chǎn)生這樣的結(jié)果呢?
原因在于在計(jì)時(shí)的時(shí)候使用了sleep方法來計(jì)時(shí),但是sleep實(shí)際上是通過阻塞線程的方式實(shí)現(xiàn)的延時(shí),如果只使用一個(gè)線程,那么自然會(huì)把僅有的這一個(gè)線程卡住。
解決方法自然是通過多線程,創(chuàng)建子線程來計(jì)時(shí),而主線程只負(fù)責(zé)主界面的部分,就不會(huì)出現(xiàn)這種一直未響應(yīng)的情況。多線程的優(yōu)勢(shì)就在于此,可以同時(shí)處理多個(gè)并發(fā)任務(wù)。
實(shí)例2-使用多線程改進(jìn)上一實(shí)例
接下來我們就開始使用多線程對(duì)第一個(gè)實(shí)例進(jìn)行改進(jìn),主線程負(fù)責(zé)主界面myGUI,而子線程負(fù)責(zé)計(jì)時(shí),其使用自定義的timer函數(shù)。
要實(shí)現(xiàn)的目標(biāo)與實(shí)例1相同,即點(diǎn)擊按鈕就開始計(jì)時(shí),共計(jì)時(shí)10s并將數(shù)字實(shí)時(shí)顯示在主界面文本框中。
在實(shí)例2中,共有兩處信號(hào)和槽函數(shù)的連接:
①點(diǎn)擊按鈕時(shí),觸發(fā)創(chuàng)建子線程槽函數(shù),此處點(diǎn)擊按鈕的信號(hào)與子線程槽函數(shù)連接
②子線程啟動(dòng)后,開始計(jì)時(shí),此處計(jì)時(shí)的信號(hào)與主界面在文本框中實(shí)時(shí)顯示數(shù)字的槽函數(shù)相連接
實(shí)例如下:
""" Pyside6# QThread多線程 實(shí)例2:使用多線程改進(jìn)實(shí)例1 """ from PySide6.QtCore import QThread, Slot, Signal from PySide6.QtWidgets import QWidget, QApplication, QPushButton, QVBoxLayout, QLabel, QTextEdit import time from time import sleep # 主界面,繼承QWidget類 class MyGUI(QWidget): def __init__(self): # 重寫構(gòu)造方法 super().__init__() self.setup() # 創(chuàng)建界面 self.bind() # 綁定函數(shù) def bind(self): self.button.clicked.connect(self.start_new_thread) # 將按鈕與開啟新線程的槽函數(shù)通過click信號(hào)相連 def setup(self): layout = QVBoxLayout() # 界面布局為垂直布局 self.setLayout(layout) # 設(shè)置layout布局 self.resize(300, 150) # 重新設(shè)置界面大小 self.label = QLabel("點(diǎn)擊按鈕開始計(jì)時(shí)") # 定義標(biāo)簽控件 self.button = QPushButton("Click!") # 定義按鈕控件 self.text_edit = QTextEdit() # 定義可編輯文本框控件 layout.addWidget(self.label) # 放置標(biāo)簽控件 layout.addWidget(self.button) # 放置按鈕控件 layout.addWidget(self.text_edit) # 放置文本框界面 def start_new_thread(self): print("啟動(dòng)新線程") self.thread1 = myThread() # 創(chuàng)建子線程thread1 self.thread1.signal_int.connect(self.update_number) # 【關(guān)鍵】將信號(hào)與槽函數(shù)連接 self.thread1.start() # 啟動(dòng)子線程thread1 @Slot(int) # 定義一個(gè)槽函數(shù), 在函數(shù)前放一個(gè)@Slot()表明其是一個(gè)槽函數(shù) def update_number(self, count): self.text_edit.setText(f"{count}") # 將計(jì)時(shí)器傳來的信號(hào)展示在文本框中 # 子線程類,繼承QThread類 class myThread(QThread): signal_int = Signal(int) # 定義信號(hào) def __init__(self): super().__init__() def run(self): self.timer() # 重寫run()方法,啟動(dòng)線程時(shí)自動(dòng)調(diào)用并運(yùn)行timer函數(shù),開始計(jì)時(shí) def timer(self): # 定義一個(gè)10s的計(jì)時(shí)器 print("開始計(jì)時(shí)") count = 0 while count < 10: time.sleep(1) count += 1 self.signal_int.emit(count) # 【關(guān)鍵】每秒發(fā)送一次信號(hào),將當(dāng)前計(jì)數(shù)數(shù)字傳至主界面顯示 print("結(jié)束計(jì)時(shí)") # 運(yùn)行應(yīng)用界面程序 if __name__ == '__main__': app = QApplication([]) # 定義一個(gè)應(yīng)用 window = MyGUI() # 定義一個(gè)界面 window.show() # 展示界面 app.exec() # 啟動(dòng)應(yīng)用
實(shí)現(xiàn)的效果如下:
可以看到,此時(shí)計(jì)時(shí)正常進(jìn)行,主界面無響應(yīng)的情況也不再發(fā)生了,這就是多線程的作用。雖然此處只使用了time阻塞線程的這一特例,但是在其他很多情況下都可以使用,尤其是項(xiàng)目較為復(fù)雜時(shí),需要同時(shí)進(jìn)行多并發(fā)的任務(wù),多線程就必不可少了。
感謝各位支持,之后還會(huì)繼續(xù)分享更多有用的知識(shí)!想要了解更多可以關(guān)注我或關(guān)注本專欄。
以上就是使用PySide多線程處理圖形界面卡頓問題詳解的詳細(xì)內(nèi)容,更多關(guān)于PySide處理圖形界面卡頓的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python實(shí)現(xiàn)釘釘發(fā)送報(bào)警消息的方法
今天小編就為大家分享一篇Python實(shí)現(xiàn)釘釘發(fā)送報(bào)警消息的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-02-02Python-OpenCV實(shí)戰(zhàn):利用 KNN 算法識(shí)別手寫數(shù)字
K-最近鄰(KNN)是監(jiān)督學(xué)習(xí)中最簡單的算法之一,KNN可用于分類和回歸問題。本文將為大家介紹的是通過KNN算法實(shí)現(xiàn)識(shí)別手寫數(shù)字。文中的示例代碼介紹詳細(xì),需要的朋友可以參考一下2021-12-12Python中max函數(shù)用于二維列表的實(shí)例
下面小編就為大家分享一篇Python中max函數(shù)用于二維列表的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-04-04Python中的True,False條件判斷實(shí)例分析
這篇文章主要介紹了Python中的True,False條件判斷的用法,實(shí)例分析了針對(duì)不同數(shù)據(jù)類型的條件判斷用法,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-01-01numpy數(shù)組疊加的實(shí)現(xiàn)示例
本文主要介紹了numpy數(shù)組疊加的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08