轉載:翻滾吧挨踢男網絡
首先來看一個例子:app
# 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()函數)。再次運行程序,你會發現如今界面已經不會被阻塞了。佈局