python GUI庫圖形界面開發(fā)之PyQt5線程類QThread詳細使用方法
QThread是Qt的線程類中最核心的底層類。由于PyQt的的跨平臺特性,QThread要隱藏所有與平臺相關的代碼
要使用的QThread開始一個線程,可以創(chuàng)建它的一個子類,然后覆蓋其它QThread.run()函數(shù)
class Thread(QThread):
def __init __(self):
super(Thread,self).__ init __()
def run(self):
#線程相關的代碼
pass
接下來創(chuàng)建一個新的線程
thread = Thread() thread.start()
可以看出,PyQt的線程使用非常簡單—-建立一個自定義的類(如thread),自我繼承自QThread ,并實現(xiàn)其run()方法即可
在使用線程時可以直接得到Thread實例,調(diào)用其start()函數(shù)即可啟動線程,線程啟動之后,會自動調(diào)用其實現(xiàn)的run()的函數(shù),該方法就是線程的執(zhí)行函數(shù)
業(yè)務的線程任務就寫在run()函數(shù)中,當run()退出之后線程就基本結束了,QThread有started和finished信號,可以為這兩個信號指定槽函數(shù),在線程啟動和結束之時執(zhí)行一段代碼進行資源的初始化和釋放操作,更靈活的使用方法是,在自定義的QThread實例中自定義信號,并將信號連接到指定的槽函數(shù),當滿足一定的業(yè)務條件時發(fā)射此信號
QThread類中的常用方法
| 方法 | 描述 |
|---|---|
| start() | 啟動線程 |
| wait() | 阻止線程,直到滿足如下條件之一 |
| 與此QThread對象關聯(lián)的線程已完成執(zhí)行(即從run返回時),如果線程完成執(zhí)行,此函數(shù)返回True,如果線程尚未啟動,也返回True | |
| 等待時間的單位是毫秒,如果時間是ULONG_MAX(默認值·),則等待,永遠不會超時(線程必須從run返回),如果等待超時,此函數(shù)將會返回False | |
| sleep() | 強制當前線程睡眠多少秒 |
QThread類中的常用信號
| 信號 | 描述 |
|---|---|
| started | 在開始執(zhí)行run函數(shù)之前,從相關線程發(fā)射此信號 |
| finished | 當程序完成業(yè)務邏輯時,從相關線程發(fā)射此信號 |
QThread的使用方法實例
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class MainWidget(QWidget):
def __init__(self, parent=None):
super(MainWidget, self).__init__(parent)
#設置標題
self.setWindowTitle('QThread多線程例子')
#實例化多線程對象
self.thread = Worker()
#實例化列表控件與按鈕控件
self.listFile = QListWidget()
self.btnStart = QPushButton('開始')
#把控件放置在柵格布局中
layout = QGridLayout(self)
layout.addWidget(self.listFile, 0, 0, 1, 2)
layout.addWidget(self.btnStart, 1, 1)
#信號與槽函數(shù)的連接
self.btnStart.clicked.connect(self.slotStart)
self.thread.sinOut.connect(self.slotAdd)
def slotAdd(self, file_inf):
#向列表控件中添加條目
self.listFile.addItem(file_inf)
def slotStart(self):
#開始按鈕不可點擊,線程開始
self.btnStart.setEnabled(False)
self.thread.start()
class Worker(QThread):
sinOut = pyqtSignal(str)
def __init__(self, parent=None):
super(Worker, self).__init__(parent)
#設置工作狀態(tài)與初始num數(shù)值
self.working = True
self.num = 0
def __del__(self):
#線程狀態(tài)改變與線程終止
self.working = False
self.wait()
def run(self):
while self.working == True:
#獲取文本
file_str = 'File index{0}'.format(self.num)
self.num += 1
# 發(fā)射信號
self.sinOut.emit(file_str)
# 線程休眠2秒
self.sleep(2)
if __name__ == '__main__':
app = QApplication(sys.argv)
demo = MainWidget()
demo.show()
sys.exit(app.exec_())
運行效果圖如下

代碼分析
在這個例子中,單擊開始按鈕,會在后臺定時讀取數(shù)據(jù),并把返回的數(shù)據(jù)顯示在界面中,首先使用以下代碼進行布局,把列表控件和按鈕控件放在柵格布局管理器中
#實例化列表控件與按鈕控件
self.listFile = QListWidget()
self.btnStart = QPushButton('開始')
#把控件放置在柵格布局中
layout = QGridLayout(self)
layout.addWidget(self.listFile, 0, 0, 1, 2)
layout.addWidget(self.btnStart, 1, 1)
然后將按鈕的clicked信號連接到槽函數(shù),單擊開始觸發(fā)槽函數(shù)
self.btnStart.clicked.connect(self.slotStart)
def slotStart(self):
#開始按鈕不可點擊,線程開始
self.btnStart.setEnabled(False)
self.thread.start()
比較復雜的是線程的信號,將線程的sinOut信號連接到slotAdd()槽函數(shù),SlotAdd()函數(shù)負責在列表控件中動態(tài)添加字符串條目
self.thread.sinOut.connect(self.slotAdd)
def slotAdd(self,file_inf):
#向列表控件中添加條目
self.listFile.addItem(file_inf)
定義一個線程類,繼承自QThread,當線程啟動時,執(zhí)行run()函數(shù)
class Worker(QThread):
sinOut = pyqtSignal(str)
def __init__(self, parent=None):
super(Worker, self).__init__(parent)
#設置工作狀態(tài)與初始num數(shù)值
self.working = True
self.num = 0
def __del__(self):
#線程狀態(tài)改變與線程終止
self.working = False
self.wait()
def run(self):
while self.working == True:
#獲取文本
file_str = 'File index{0}'.format(self.num)
self.num += 1
# 發(fā)射信號
self.sinOut.emit(file_str)
# 線程休眠2秒
self.sleep(2)
多線程失敗案例
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
global sec
sec=0
def setTime():
global sec
sec+=1
#Led顯示數(shù)字+1
lcdNumber.display(sec)
def work():
#計時器每秒計數(shù)
timer.start(1000)
for i in range(200000000):
pass
timer.stop()
if __name__ == '__main__':
app=QApplication(sys.argv)
top=QWidget()
top.resize(300,120)
#垂直布局
layout=QVBoxLayout(top)
#添加一個顯示面板
lcdNumber=QLCDNumber()
layout.addWidget(lcdNumber)
button=QPushButton('測試')
layout.addWidget(button)
timer=QTimer()
#每次計時結束,觸發(fā)setTime
timer.timeout.connect(setTime)
button.clicked.connect(work)
top.show()
sys.exit(app.exec_())
失敗效果圖如下

長時間停留在此界面,知道多線程任務完成后,此界面才會動,當耗時程序非常大時,就會造成程序運行失敗的假象,實際還是在后臺運行的,只是沒有顯示在主窗口的界面上,當然用戶體驗也就非常差,那么如何解決這個問題呢,下面實例三進行解答
分離UI主線程與工作線程實例
import sys
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):
#開始進行循環(huán)
for i in range(2000000000):
pass
# 循環(huán)完畢后發(fā)出信號
self.trigger.emit()
def countTime():
global sec
sec += 1
# LED顯示數(shù)字+1
lcdNumber.display(sec)
def work():
# 計時器每秒計數(shù)
timer.start(1000)
# 計時開始
workThread.start()
# 當獲得循環(huán)完畢的信號時,停止計數(shù)
workThread.trigger.connect(timeStop)
def timeStop():
#定時器停止
timer.stop()
print("運行結束用時", lcdNumber.value())
global sec
sec = 0
if __name__ == "__main__":
app = QApplication(sys.argv)
top = QWidget()
top.resize(300, 120)
# 垂直布局類QVBoxLayout
layout = QVBoxLayout(top)
# 加顯示屏,按鈕到布局中
lcdNumber = QLCDNumber()
layout.addWidget(lcdNumber)
button = QPushButton("測試")
layout.addWidget(button)
#實例化定時器與多線程類
timer = QTimer()
workThread = WorkThread()
button.clicked.connect(work)
# 每次計時結束,觸發(fā) countTime
timer.timeout.connect(countTime)
top.show()
sys.exit(app.exec_())
運行效果,程序主界面的數(shù)值會每秒增加1,直到循環(huán)結束,這里就避免了主界面長時間不動的尷尬!

QThread線程事件處理實例
對于執(zhí)行很耗時的程序來說,由于PyQt需要等待程序執(zhí)行完畢才能進行下一步,這個過程表現(xiàn)在界面上就是卡頓,而如果需要執(zhí)行這個耗時程序時不斷的刷新界面。那么就可以使用QApplication.processEvents(),那么就可以一邊執(zhí)行耗時程序,一邊刷新界面的功能,給人的感覺就是程序運行很流暢,因此QApplicationEvents()的使用方法就是,在主函數(shù)執(zhí)行耗時操作的地方,加入QApplication.processEvents()
import sys,time
from PyQt5.QtWidgets import QWidget,QPushButton,QApplication,QListWidget,QGridLayout
class WinForm(QWidget):
def __init__(self,parent=None):
super(WinForm, self).__init__(parent)
#設置標題與布局方式
self.setWindowTitle('實時刷新界面的例子')
layout=QGridLayout()
#實例化列表控件與按鈕控件
self.listFile=QListWidget()
self.btnStart=QPushButton('開始')
#添加到布局中指定位置
layout.addWidget(self.listFile,0,0,1,2)
layout.addWidget(self.btnStart,1,1)
#按鈕的點擊信號觸發(fā)自定義的函數(shù)
self.btnStart.clicked.connect(self.slotAdd)
self.setLayout(layout)
def slotAdd(self):
for n in range(10):
#獲取條目文本
str_n='File index{0}'.format(n)
#添加文本到列表控件中
self.listFile.addItem(str_n)
#實時刷新界面
QApplication.processEvents()
#睡眠一秒
time.sleep(1)
if __name__ == '__main__':
app=QApplication(sys.argv)
win=WinForm()
win.show()
sys.exit(app.exec_())

本文詳細介紹了python GUI庫PyQt5的線程類QThread詳細使用方法,想了解更多相關知道請查看下面的相關鏈接
相關文章
Python基于socket模塊實現(xiàn)UDP通信功能示例
這篇文章主要介紹了Python基于socket模塊實現(xiàn)UDP通信功能,結合實例形式分析了Python使用socket模塊實現(xiàn)IPV4協(xié)議下的UDP通信客戶端與服務器端相關操作技巧,需要的朋友可以參考下2018-04-04
Python中使用logging和traceback模塊記錄日志和跟蹤異常
今天小編就為大家分享一篇關于Python中使用logging和traceback模塊記錄日志和跟蹤異常,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-04-04
python中json格式數(shù)據(jù)輸出的簡單實現(xiàn)方法
下面小編就為大家?guī)硪黄猵ython中json格式數(shù)據(jù)輸出的簡單實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-10-10
Python3讀取Excel數(shù)據(jù)存入MySQL的方法
今天小編就為大家分享一篇Python3讀取Excel數(shù)據(jù)存入MySQL的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-05-05
使用Python判斷質(zhì)數(shù)(素數(shù))的簡單方法講解
這篇文章主要介紹了使用Python判斷質(zhì)數(shù)(素數(shù))的簡單方法講解,經(jīng)常被用來做科學計算的Python處理這種小問題當然手到擒來^_-需要的朋友可以參考下2016-05-05
python GUI庫圖形界面開發(fā)之PyQt5狀態(tài)欄控件QStatusBar詳細使用方法實例
這篇文章主要介紹了python GUI庫圖形界面開發(fā)之PyQt5狀態(tài)欄控件QStatusBar詳細使用方法實例,需要的朋友可以參考下2020-02-02

