1. 程式人生 > >PyQt5中非同步重新整理UI和Python中的多執行緒總結

PyQt5中非同步重新整理UI和Python中的多執行緒總結

目前任務需要做一個介面程式,PyQt是非常方便的選擇,QT豐富的控制元件以及python方便的程式設計。近期遇到介面中執行一些後臺任務時介面卡死的情況,解決了在這裡記錄下。

PyQt

PyQt簡介

PyQtQt的python介面,PyQt的文件較少,但介面和函式可以完全參照Qt,繼承了Qt中大量的控制元件以及訊號機制,十分方便。以下簡介一個基本的PyQt程式。
- 需要匯入的類主要來自三個包
- from PyQt5.QtWidgets import 常用的控制元件
- PyQt5.QtCore 核心功能類,如QTQThreadpyqtSignal


- PyQt5.QtGui UI類,如QFont
- 基礎的程式結構:

class Example(QWidget):
    def __init__(self):
        super()__init__()
        self.setupUI()

    def setupUI():
        self.show()
        pass
        # 設定UI
if __name__ == '__main__':
    app = QApplication(sys.argv) # 啟動app
    ex = Example()   # 例項化一個自己派生的
# 也可以例項化庫中的控制元件 # q = QPushButton() # q.show() sys.exit(app.exec_())

總體來說:
1. 首先例項化APP
2. 例項化預定義控制元件或者自己派生自庫中的控制元件,記得呼叫show()函式
3. 執行並安全退出

Python中的多執行緒

python中的多執行緒使用較為方便,主要使用threading.Thread類:
1. 執行緒啟動使用start()函式
2. 如果需要等待執行緒執行使用join,這樣主執行緒會阻塞

實現方式一

直接傳入函式,啟動執行緒,可以傳入引數

import time, threading
def threadFunction():
    while True:
        print(11111)
        time.sleep()
# 用於命名,可以通過threading.current_thread().name獲得
t = threading.Thread(target=threadFunction, name='funciton')
# 如果執行緒有引數
t = threading.Thread(target=threadFunction, args=(), name='funciton')
t.start()

實現方式二

繼承Thread,重寫run方法

from threading import Thread
import time

class Example(Thread):
    def __init__(self):
        super().__init__()

    def run(self):
        while True:
            time.sleep(1)
            print(11111111)

if __name__ == '__main__':
    a = Example()
    a.start()
    a.join()
    print(222222222)

注意:
1. 使用join方法會讓主執行緒阻塞在這裡,等待子執行緒結束,在裡面可以設定阻塞的時間
2. a.setDaemon(True)start前設定,可以保證在主執行緒終止時,子執行緒也終止

訊號機制

QT中的訊號機制能夠方便的編寫回調。
1. 很多控制元件都有預定的訊號如clicked,直接使用clicked.connect連線槽函式即可。
2. 繼承自Qt的類,然後自定義一個signal類變數,在例項連線訊號就可以了

class Example(QWidget):
    signal = pyqtSignal()    # 括號裡填寫訊號傳遞的引數
    # 發射訊號
    def func(self):
        self.signal.emit()

# 使用訊號
a = Example()
a.signal.connect(callback)

# 槽函式
def callback():
    pass

UI重新整理

在介面中,通常用會有一些按鈕,點選後觸發事件,比如去下載一個檔案或者做一些操作,這些操作會耗時,如果不能及時結束,主執行緒將會阻塞,這樣介面就會出現未響應的狀態,因此必須使用多執行緒來解決這個問題。
注意:
1. PyQt5不能在子執行緒中重新整理執行緒,這樣會造成介面卡死,因此不能使用常規的多執行緒重新整理UI。
2. 但是又必須要實現子執行緒和主執行緒之間的通訊,否則無法得知任務是否完成。因此使用PyQt5中的QThread,這樣既可以使用訊號機制,又能夠使用多執行緒。
3. 當啟動多執行緒後,註冊訊號,槽函式為主執行緒中的函式,當任務完成後,發射訊號,在主執行緒中對UI進行更新。

注:由於需要註冊訊號,thread需要是繼承自QThread的類

class Example(QThread):
    signal = pyqtSignal()    # 括號裡填寫訊號傳遞的引數
    def __init__(self):
        super().__init__()

    def __del__(self):
        self.wait()

    def run(self):
        # 進行任務操作
        self.signal.emit()    # 發射訊號

# UI類中
def buttonClick(self)
    self.thread = Example()
    self.thread.signal.connect(self.callback)
    self.thread.start()    # 啟動執行緒

def callbakc(self):
    pass

如有錯誤,歡迎指正~