pyqt5?子線程如何操作主線程GUI(示例代碼)
一.簡介
在使用pyqt5編寫gui時遇到兩個問題,會導致界面崩潰,今天就圍繞這兩個問題來簡單說明和改進。
1.在主線程中使用while無限循環(huán)會導致界面崩潰
2.在子線程中操作主線程gui會導致界面崩潰
二.步驟說明
1.在主線程中使用while無限循環(huán)會導致界面崩潰
1)錯誤代碼
import sys from PyQt5.QtWidgets import QPushButton, QTextEdit, QApplication, QHBoxLayout, QWidget class FileChooserApp(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): button = QPushButton("按鈕") self.reviewEdit = QTextEdit() self.reviewEdit.move(100, 100) button.clicked.connect(self.send) hbox1 = QHBoxLayout() # 創(chuàng)建一個水平布局 hbox1.addWidget(button) # 添加按鈕到水平布局中 hbox1.addStretch(1) # 設(shè)置水平比例間距 hbox1.addWidget(self.reviewEdit) # 添加按鈕到水平布局中 self.setLayout(hbox1) # 添加到布局器 self.setWindowTitle('文件選擇器') self.setGeometry(300, 300, 500, 500) def send(self): """ 事件 :return: """ while True: """ 邏輯代碼 """ self.reviewEdit.setText("測試") if __name__ == '__main__': app = QApplication(sys.argv) ex = FileChooserApp() ex.show() sys.exit(app.exec_())
2)崩潰原因
我們先來說下while崩潰的問題,這邊我設(shè)置的循環(huán)是一個無限循環(huán),不會給 GUI 事件循環(huán)任何運行的機會。在 PyQt 或其他 GUI 框架中,GUI 的事件循環(huán)(例如按鈕點擊、窗口移動等)必須在單獨的線程中運行,以保持 GUI 的響應(yīng)性
3)改進方法
將循環(huán)體在一個子線程中執(zhí)行,就可以避免這個問題,代碼如下。
import sys import threading from PyQt5.QtWidgets import QPushButton, QTextEdit, QApplication, QHBoxLayout, QWidget class FileChooserApp(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): button = QPushButton("按鈕") self.reviewEdit = QTextEdit() self.reviewEdit.move(100, 100) button.clicked.connect(self.send) hbox1 = QHBoxLayout() # 創(chuàng)建一個水平布局 hbox1.addWidget(button) # 添加按鈕到水平布局中 hbox1.addStretch(1) # 設(shè)置水平比例間距 hbox1.addWidget(self.reviewEdit) # 添加按鈕到水平布局中 self.setLayout(hbox1) # 添加到布局器 self.setWindowTitle('文件選擇器') self.setGeometry(300, 300, 500, 500) def send(self): """ 事件 :return: """ def send_a(): while True: """ 邏輯代碼 """ print("123") send_thread = threading.Thread(target=send_a) # 啟動線程 send_thread.start() if __name__ == '__main__': app = QApplication(sys.argv) ex = FileChooserApp() ex.show() sys.exit(app.exec_())
2.在子線程中操作主線程gui會導致界面崩潰
1)錯誤代碼
import sys import threading import time from PyQt5.QtWidgets import QPushButton, QTextEdit, QApplication, QHBoxLayout, QWidget class FileChooserApp(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): button = QPushButton("按鈕") self.reviewEdit = QTextEdit() self.reviewEdit.move(100, 100) button.clicked.connect(self.send) hbox1 = QHBoxLayout() # 創(chuàng)建一個水平布局 hbox1.addWidget(button) # 添加按鈕到水平布局中 hbox1.addStretch(1) # 設(shè)置水平比例間距 hbox1.addWidget(self.reviewEdit) # 添加按鈕到水平布局中 self.setLayout(hbox1) # 添加到布局器 self.setWindowTitle('文件選擇器') self.setGeometry(300, 300, 500, 500) def send(self): """ 事件 :return: """ def send_a(): while True: """ 邏輯代碼 """ self.reviewEdit.setText("設(shè)置文案") send_thread = threading.Thread(target=send_a) # 啟動線程 send_thread.start() if __name__ == '__main__': app = QApplication(sys.argv) ex = FileChooserApp() ex.show() sys.exit(app.exec_())
2)崩潰原因
上述中試圖在子線程send_a方法中給文本編輯器設(shè)置文案。這是不允許的,因為 PyQt 和大多數(shù) GUI 框架一樣,要求所有的 GUI 更新必須在主線程(也稱為 GUI 線程)中執(zhí)行。
3)改進方法
既然在子線程中無法操作主線程gui更新,那么只能在主線程中去執(zhí)行,這就需要信號與槽的配合了。我們先來自定義一個信號
class YourThread(QObject): show_warning_signal = pyqtSignal() def run(self): self.show_warning_signal.emit()
在初始化的時候去實例化YourThread類,連線信號與槽
class FileChooserApp(QMainWindow): def __init__(self): super().__init__() self.initUI() self.your = YourThread() self.your.show_warning_signal.connect(self.settext)
接著在子線程中直接去觸發(fā)信號即可
def send(self): def send_a(): while True: """ 循環(huán)體 """ self.your.run() time.sleep(2) send_thread = threading.Thread(target=send_a) # 啟動線程 send_thread.start()
執(zhí)行每次循環(huán)需要等待2s,避免出現(xiàn)無限循環(huán)導致應(yīng)用程序凍結(jié)、響應(yīng)緩慢或其他線程相關(guān)的問題
三.實例
import sys import threading import time from PyQt5.QtCore import QObject, pyqtSignal from PyQt5.QtWidgets import QPushButton, QTextEdit, QApplication, QHBoxLayout, QWidget class YourThread(QObject): show_warning_signal = pyqtSignal() def run(self): self.show_warning_signal.emit() class FileChooserApp(QWidget): def __init__(self): super().__init__() self.initUI() self.your = YourThread() self.your.show_warning_signal.connect(self.settext) def initUI(self): button = QPushButton("按鈕") self.reviewEdit = QTextEdit() self.reviewEdit.move(100, 100) button.clicked.connect(self.send) hbox1 = QHBoxLayout() # 創(chuàng)建一個水平布局 hbox1.addWidget(button) # 添加按鈕到水平布局中 hbox1.addStretch(1) # 設(shè)置水平比例間距 hbox1.addWidget(self.reviewEdit) # 添加按鈕到水平布局中 self.setLayout(hbox1) # 添加到布局器 self.setWindowTitle('文件選擇器') self.setGeometry(300, 300, 500, 500) def send(self): """ 事件 :return: """ def send_a(): while True: """ 邏輯代碼 """ self.your.run() time.sleep(2) send_thread = threading.Thread(target=send_a) # 啟動線程 send_thread.start() def settext(self): self.reviewEdit.setText("123") if __name__ == '__main__': app = QApplication(sys.argv) ex = FileChooserApp() ex.show() sys.exit(app.exec_())
到此這篇關(guān)于pyqt5 子線程如何操作主線程GUI的文章就介紹到這了,更多相關(guān)pyqt5 子線程操作主線程GUI內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python中的插值 scipy-interp的實現(xiàn)代碼
這篇文章主要介紹了python中的插值 scipy-interp的實現(xiàn)代碼,需要的朋友可以參考下2018-07-07python人工智能tensorflow函數(shù)tensorboard使用方法
這篇文章主要為大家介紹了python人工智能tensorflow函數(shù)tensorboard使用方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-05-05