1. 程式人生 > >PyQt5學習筆記14----初識pyqt多執行緒操作

PyQt5學習筆記14----初識pyqt多執行緒操作

首先來看一個例子:

# coding=utf-8
__author__ = 'a359680405'

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

global sec
sec=0
def setTime():
    global  sec
    sec+=1
    lcdNumber.display(sec)          #LED顯示數字+1

def work():
    timer.start(1000)               #計時器每秒計數
    for i in range(2000000000):
       pass
    timer.stop()

app=QApplication([])
top=QWidget()
layout=QVBoxLayout(top)             #垂直佈局類QVBoxLayout;
lcdNumber=QLCDNumber()              #加個顯示屏
layout.addWidget(lcdNumber)
button=QPushButton("測試")
layout.addWidget(button)

timer=QTimer()
timer.timeout.connect(setTime)      #每次計時結束,觸發setTime
button.clicked.connect(work)

top.show()
app.exec()


      我們的主介面有一個用於顯示時間的 LCD 數字面板還有一個用於啟動任務的按鈕。程式的目的是使用者點選按鈕,開始一個非常耗時的運算(程式中我們以一個 2000000000 次的迴圈來替代這個非常耗時的工作,在真實的程式中,這可能是一個網路訪問,可能是需要複製一個很大的檔案或者其它任務),同時 LCD 開始顯示逝去的毫秒數。毫秒數通過一個計時器QTimer進行更新。計算完成後,計時器停止。這是一個很簡單的應用,也看不出有任何問題。但是當我們開始執行程式時,問題就來了:點選按鈕之後,程式介面直接停止響應,直到迴圈結束才開始重新更新,於是計時器使用顯示0。


      有經驗的開發者立即指出,這裡需要使用執行緒。這是因為 Qt 中所有介面都是在 UI 執行緒中(也被稱為主執行緒,就是執行了QApplication::exec()的執行緒),在這個執行緒中執行耗時的操作(比如那個迴圈),就會阻塞 UI 執行緒,從而讓介面停止響應。介面停止響應,使用者體驗自然不好,不過更嚴重的是,有些視窗管理程式會檢測到你的程式已經失去響應,可能會建議使用者強制停止程式,這樣一來你的程式可能就此終止,任務再也無法完成。所以,為了避免這一問題,我們要使用 QThread 開啟一個新的執行緒:
# coding=utf-8
__author__ = 'a359680405'

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

global sec
sec=0

class WorkThread(QThread):
    trigger = pyqtSignal()
    def __int__(self):
        super(WorkThread,self).__init__()

    def run(self):
        for i in range(203300030):
            pass
        self.trigger.emit()         #迴圈完畢後發出訊號

def countTime():
    global  sec
    sec+=1
    lcdNumber.display(sec)          #LED顯示數字+1

def work():
    timer.start(1000)               #計時器每秒計數
    workThread.start()              #計時開始
    workThread.trigger.connect(timeStop)   #當獲得迴圈完畢的訊號時,停止計數

def timeStop():
    timer.stop()
    print("執行結束用時",lcdNumber.value())
    global sec
    sec=0

app=QApplication([])
top=QWidget()
layout=QVBoxLayout(top)             #垂直佈局類QVBoxLayout;
lcdNumber=QLCDNumber()              #加個顯示屏
layout.addWidget(lcdNumber)
button=QPushButton("測試")
layout.addWidget(button)

timer=QTimer()
workThread=WorkThread()

button.clicked.connect(work)
timer.timeout.connect(countTime)      #每次計時結束,觸發setTime

top.show()
app.exec()


        我增加了一個WorkerThread類。WorkerThread繼承自QThread類,重寫了其run()函式。可以認為,run()函式就是新的執行緒需要執行的程式碼。在這裡就是要執行這個迴圈,然後發出計算完成的訊號。而在按鈕點選的槽函式中,使用work()中的workThread.start()函式啟動一個執行緒(注意,這裡不是run()函式)。再次執行程式,你會發現現在介面已經不會被阻塞了。