Pyqt5實現多線程程序

主從架構

Pyqt常常使用**主從架構(Master-Workers 架構)**來避免界面卡死的情況。

Master-Workers 架構就像它的名字,一個master統領著幾個workers一起干活。其中某個worker倒下了不會導致整體任務失敗。matser不用干活,因此可以專心指揮workers。

在qt5中,master代表主線程,主要維持主界面的運行。當觸發某項耗時耗力的任務時,主線程將這項任務分配給其他線程(workers)來做。其他線程出現了災難性的錯誤,不會影響到主線程,因此程序不會完全崩潰。且主線程不承擔耗時耗力的任務,因此避免了復雜運算時主界面卡頓的問題。

進程和線程詳見1

pyqt5多線程的架構一般由三個模塊實現:

  • Gui.py:只存放GUI界面,一般是Qt Designer生成的代碼,無需做任何修改
  • Thread.py:從線程,主要的邏輯代碼都放在這里。接收主線程的指令,并向主線程返回信號。
  • Main.py:主線程,負責運行GUI界面,向從線程發送指令并接收從線程返回的信號。

GUI模塊

Qt Designer保存的文件為Gui.ui的格式,使用下面命令轉為Gui.py

pyuic5 Gui.ui -o Gui.py

轉換后的代碼結構如下,我們不需要對這個代碼做任何修改。

# -*- coding: utf-8 -*-# Form implementation generated from reading ui file 'mainwindow.ui'
#
# Created by: PyQt5 UI code generator 5.5.1
#
# WARNING! All changes made in this file will be lost!from PyQt5 import QtCore, QtGui, QtWidgetsclass Ui_MainWindow(object): # 注意這個類名,后面在Main.py中找到它def setupUi(self, MainWindow):MainWindow.setObjectName("MainWindow")# ------- 省略很多行... ------- #self.retranslateUi(MainWindow)QtCore.QMetaObject.connectSlotsByName(MainWindow)def retranslateUi(self, MainWindow):_translate = QtCore.QCoreApplication.translateMainWindow.setWindowTitle(_translate("MainWindow", "標題"))# ------- 省略很多行... ------- #

不同線程間的信號與槽

在討論主線程和從線程之前,首先要明確線程間傳遞信號的方法2

信號與槽機制示意圖

主 -> 從

主線程到從線程的信號就是最基本信號與槽的機制,使用槽函數來與從線程通信。一般是Wight被clicked,然后觸發槽函數。傳遞的路徑為:1.觸發信號事件 -> 2.信號clicked -> 3.槽函數接收信號并運行。使用以下語句綁定槽函數:

from Thread import New_thread # 從線程的引用class MainWindow(QMainWindow, Ui_MainWindow):def __init__(self, parent=None) -> None:super(MainWindow,self).__init__(parent)self.setupUi(self)# ----------------------------------------- ## ↓↓↓↓↓↓↓ 不用管上面的代碼,主要看下面 ↓↓↓↓↓↓↓ ## ----------------------------------------- #self.thread = None # 先預定義一個從線程的實例屬性,這里無需將從線程實例化# self.btn為Ui_MainWindow中定義的按鈕,這里將按鈕點擊的信號與槽函數self.func連接起來self.btn.clicked.connect(self.func) def func(self):self.thread = New_thread() # 在槽函數中實例化從線程,然后就可以操作從線程了self.thread.start()pass

有時我們需要向槽函數傳遞參數,一般使用偏函數或lambda,偏函數可參見3

from functools import partial # 偏函數的引用
from Thread import New_thread # 從線程的引用class MainWindow(QMainWindow, Ui_MainWindow):def __init__(self, parent=None) -> None:super(MainWindow,self).__init__(parent)self.setupUi(self)# ----------------------------------------- ## ↓↓↓↓↓↓↓ 不用管上面的代碼,主要看下面 ↓↓↓↓↓↓↓ ## ----------------------------------------- #self.thread = None # 先預定義一個從線程的實例屬性,這里無需將從線程實例化# 第一種方法:這個槽函數被寫成了偏函數的形式 partial(self.func, param1, param2)self.btn1.clicked.connect(partial(self.func, param1=1, param2=2)) # 第二種方法:這個槽函數被寫成了lambda的形式 lambda:self.func(param1=1, param2=2)self.btn2.clicked.connect(lambda:self.func(param1=1, param2=2))# 這個槽函數監聽了兩個信號哦def func(self, param1, param2):# 在槽函數中實例化從線程,然后就可以操作從線程了self.thread = New_thread(param1, param2) # 從線程實例化也可以放在__init__里面,但我喜歡放在這。self.thread.start()pass

從 -> 主

從線程向主線程傳遞信號一般使用自定義信號,觸發后,從線程的自定義信號傳遞給主線程連接的槽函數。觸發的路徑為1.從線程觸發信號emit -> 2.聲明信號pyqtSignal -> 3.傳遞給主線程連接的槽函數。使用下面代碼建立自定義信號。

先在Thread.py中定義信號:

# Thread.py
from PyQt5.QtCore import QThread, pyqtSignalclass New_Thread(QThread):# 聲明定義信號,注意它必須是類屬性。mySignal = pyqtSignal(int,str) # 后面的參數是信號的數據類型def __init__(self) -> None:super(New_Thread, self).__init__(parent)pass def run(self):pass# ------------------------------------------ ## ↓↓↓↓↓↓↓ 上面的兩個函數不用理會,看下面 ↓↓↓↓↓↓↓ ## ------------------------------------------ ## 下面是從線程的邏輯代碼def func(self):# ------- 省略很多邏輯代碼... ------- ## 向主線程發送信號self.mySignal.emit(1,"Hello, Pyqt5")

在主線程Main.py中監聽信號并連接到槽:

# Main.py
from Thread import New_thread # 從線程的引用class MainWindow(QMainWindow, Ui_MainWindow):def __init__(self, parent=None) -> None:super(MainWindow,self).__init__(parent)self.setupUi(self)# ----------------------------------------- ## ↓↓↓↓↓↓↓ 不用管上面的代碼,主要看下面 ↓↓↓↓↓↓↓ ## ----------------------------------------- #def func1(self):self.thread = New_thread() # 從線程實例化(也可以放在__init__里面)self.thread.start()# 監聽從線程發出的信號,并連接到槽函數func2# 記得嗎?mySignal發出了兩個數據,一個是int類型,一個str類型self.thread.mySignal.connect(self.func2) # 槽函數接收了從線程的信號def func2(self, param1:int, param2:str):pass

主線程Main模塊

主線程的作用是維護UI界面運行,下面給出Main模塊的一般架構

import sys # 顯示ui界面必要的引用
from PyQt5.QtWidgets import QMainWindow, QApplication # 顯示ui界面必要的引用
from GUI import * # 引用Qt Designer生成的GUI模塊
from Thread import New_thread # 從線程的引用# 第一個父類是PyQt5.QtWidgets.QMainWindow(取決于你在Qt Designer選擇的窗口類型)
# 第二個父類是GUI.Ui_MainWindow
class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self, parent=None) -> None:super(MainWindow,self).__init__(parent)self.setupUi(self) # 初始化UI界面self.thread = None # 先預定義一個從線程的實例屬性,這里無需將從線程實例化self.btn1.clicked.connect(self.func1) # 綁定控件的槽函數,以啟動從線程self.thread.finished.connect(self.func3) # 監聽線程是否完成任務,以結束從線程# 省略一萬行綁定槽函數的代碼...# 定義槽函數,這里可以放入從線程。def func1(self):self.thread = New_Thread() # 實例化一個從函數self.thread.start()self.thread.mySignal.connect(self.func2) # 監聽從線程的信號,并綁定槽函數# 定義響應從線程信號的槽函數def func2(self,param:int):pass# 定義結束從線程的槽函數def func3(self):self.thread.stop()# 省略一萬個槽函數...if __name__ == '__main__':# 任何一個qt應用都必須有且僅有一個QApplication對象# sys.argv是一組命令行參數的列表。# 這行代碼就是實例化一個QApplicationapp = QApplication(sys.argv) # 主線程實例化main_window = MainWindow()# 顯示窗口main_window.show()# sys.exit()是Python退出進程的函數# QApplication.exec_()的功能是“qt程序進入主循環,直到exit()被調用”# 沒有exec_()的話,程序不會進入主循環,會閃退。沒有sys.exit()的話,程序退出后進程不會結束。sys.exit(app.exec_())

從線程Thread模塊

from PyQt5.QtCore import QThread, pyqtSignal
from functools import partialclass New_Thread(QThread):# 聲明定義信號,注意它必須是類屬性。mySignal = pyqtSignal(int,str) # 后面的參數是信號的數據類型finishedSignal = pyqtSignal() # 線程完成的信號def __init__(self) -> None:super(New_Thread, self).__init__(parent)# run()是父類的方法,這里要重寫run方法# 將邏輯代碼放在run里面,當主線程調用thead.start()時會自動運行run函數。def run(self):# 省略一萬行代碼self.finishedSignal.emit()# 停止線程def stop(self):self.isRunning = False # isRunning是父類的屬性,可以停止線程。

  1. 進程和線程 ??

  2. 信號與槽函數 ??

  3. 偏函數 ??

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/163142.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/163142.shtml
英文地址,請注明出處:http://en.pswp.cn/news/163142.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

分布式鎖之基于redis實現分布式鎖(二)

2. 基于redis實現分布式鎖 2.1. 基本實現 借助于redis中的命令setnx(key, value),key不存在就新增,存在就什么都不做。同時有多個客戶端發送setnx命令,只有一個客戶端可以成功,返回1(true);其他…

市場是變化的?這種悖論fpmarkets澳福一秒打破

你是不是始終認為市場是經常變化的,其實這是不對的,這種認識fpmarkets澳福今天一秒打破。 市場經常變化嗎?眾多投資者無需過多思考,就認為答案是肯定的。因為無論是在互聯網的哪個角落,都可以看到這樣的信息。即使我們沒有深入研…

NLP基本知識

NLP基本知識 詞嵌入&詞向量 詞嵌入(Word Embedding)是一種將單詞或文本轉化為向量表示的技術,它在自然語言處理(NLP)中廣泛應用。詞嵌入的目標是將文本數據映射到一個低維度的向量空間中,以便計算機可…

Python---函數的嵌套(一個函數里面又調用了另外一個函數)詳解

函數嵌套調用------就是一個函數里面又調用了另外一個函數。 基本語法: # 定義 函數B def funcB():print(這是funcB函數的函數體部分...)# 定義 函數A def funcA():print(- * 80) # 這一行為了更好區分print(這是funcA函數的函數體部分...)# 假設我們在調用funcA…

設計模式-Adapter

定義 適配器設計模式是一種結構型設計模式,用于將一個類的接口變換成客戶端所期待的另一種接口,從而使原本因接口不匹配而無法在一起工作的兩個類能夠在一起工作。 適配器模式包括三種形式:類適配器模式、對象適配器模式、接口適配器模式&a…

Ubuntu18 Opencv3.4.12 viz 3D顯示安裝、編譯、使用、移植

Opencv3.*主模塊默認包括兩個3D庫 calib3d用于相機校準和三維重建 ,viz用于三維圖像顯示,其中viz是cmake選配。 參考: https://docs.opencv.org/3.4.12/index.html 下載linux版本的源碼 sources。 查看cmake apt list --installed | grep…

App Cleaner Uninstaller Pro 一鍵清理,徹底卸載Mac應用

隨著科技的不斷發展,Mac電腦已經成為許多用戶工作和娛樂的首選。然而,隨著時間的推移,我們的Mac電腦上可能會堆積大量的無效文件和冗余數據,這不僅占用了寶貴的磁盤空間,還可能影響到系統的運行速度。為了解決這一問題…

基于51單片機zigbee溫室大棚監控系統

**單片機設計介紹,基于51單片機zigbee溫室大棚監控系統 文章目錄 一 概要二、功能設計設計思路 三、 軟件設計原理圖 五、 程序六、 文章目錄 一 概要 基于51單片機和Zigbee技術的溫室大棚監控系統是一種用于監測和控制溫室大棚環境的設備。以下是一個基本的設計介…

STM32 CAN通信自定義數據包多幀連發亂序問題

場景: can標準幀中每一幀只能傳輸8字節,而應用中傳輸一包的內容往往超過8字節,因此需要把一個包拆成多個幀發送,接收端才把收到的多幀重新組裝成一個完整的包 問題描述 在一問一答的兩塊板間通信,多幀連發是能夠按照…

UDP分片和丟包與TCP效果對比

UDP 分片 與 丟包,UDP 真的比 TCP 高效嗎? UDP(用戶數據報協議)和TCP(傳輸控制協議)在很多方面都有顯著的區別。總體來說,TCP更適合需要可靠傳輸的應用,例如網頁瀏覽、電子郵件等&a…

信創系列之大數據,分布式數據庫產業鏈跟蹤梳理筆記…

并購優塾 投行界的大叔,大叔界的投行 【產業鏈地圖,版權、內容與免責聲明】1)版權:版權所有,違者必究,未經許可不得翻版、摘編、拷貝、復制、傳播。2)尊重原創:如有引用未標注來源…

CentOS 7啟動時報“Started Crash recovery kernel arming.....shutdown....”問題處理過程

有臺虛擬機由于CPU負載過高而宕機,宕機重啟后停在“Started Crash recovery kernel arming…shutdown…”階段,如下所示: 重置虛擬機,進入grub菜單,按e編輯啟動選項,在linux16 行末,加上&…

【考研】數據結構(更新到循環鏈表)

聲明&#xff1a;所有代碼都可以運行&#xff0c;可以直接粘貼運行&#xff08;只有庫函數沒有聲明&#xff09; 線性表的定義和基本操作 基本操作 定義 靜態&#xff1a; #include<stdio.h> #include<stdlib.h>#define MaxSize 10//靜態 typedef struct{int d…

【追求卓越02】數據結構--鏈表

引導 今天我們進入鏈表的學習&#xff0c;我相信大家對鏈表都很熟悉。鏈表和數組一樣&#xff0c;作為最基礎的數據結構。在我們的工作中常常會使用到。但是我們真的了解到數組和鏈表的區別嗎&#xff1f;什么時候使用數組&#xff0c;什么時候使用鏈表&#xff0c;能夠正確的選…

監控員工上網有什么軟件

監控員工上網的軟件主要用于監控員工在工作時間內的網絡行為&#xff0c;包括瀏覽網頁、使用社交媒體、發送郵件等。通過監控員工上網行為&#xff0c;企業管理者可以更好地了解員工的工作狀態和行為&#xff0c;規范員工的上網行為&#xff0c;提高工作效率&#xff0c;同時也…

SSL證書對網站的作用及影響?

SSL證書作為當下互聯網的重要安全件&#xff0c;包括搜索引擎的收錄、網站是否具備信任的條件以及HTTP2.0傳輸協議的相互作用等&#xff0c;尤其是瀏覽器對古老的http協議警告提示不安全將直接影響到用戶的信任度以及品牌形象&#xff0c;對于網站來說可謂是必不可少。 SSL證書…

Webstorm 插件文件目錄顏色分析——白藍綠紅黃灰

Webstorm 插件文件目錄【白色、藍色、綠色、紅色、黃色、灰色】對應當前文件發生什么了&#xff0c;即文件夾當前狀態。 WebStrom配置好git或SVN后文件顏色代表的含義&#xff1a; 白色&#xff1a;本地無修改內容 藍色&#xff1a;文件內容有修改&#xff0c;暫未提交到git…

python命令行 引導用戶填寫可用的ip地址和端口號

字多不看&#xff0c;直接體驗 待補充 演示代碼 # -*- coding:UTF-8 -*- """ author: dyy contact: douyaoyuan126.com time: 2023/11/23 10:29 file: 引導用戶填寫可用的ip地址和端口號.py desc: xxxxxx """# region 引入必要的依賴 import …

C語言-判斷上三角矩陣

上三角矩陣指主對角線以下的元素都為0的矩陣&#xff1b;主對角線為從矩陣的左上角至右下角的連線。 本題要求編寫程序&#xff0c;判斷一個給定的方陣是否上三角矩陣。 輸入格式&#xff1a; 輸入第一行給出一個正整數T&#xff0c;為待測矩陣的個數。接下來給出T個矩陣的信…

【LeetCode:2304. 網格中的最小路徑代價 | dijkstra(迪杰斯特拉)】

&#x1f680; 算法題 &#x1f680; &#x1f332; 算法刷題專欄 | 面試必備算法 | 面試高頻算法 &#x1f340; &#x1f332; 越難的東西,越要努力堅持&#xff0c;因為它具有很高的價值&#xff0c;算法就是這樣? &#x1f332; 作者簡介&#xff1a;碩風和煒&#xff0c;…