溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

PyQt5中如何使用QThread多線程模塊

發(fā)布時(shí)間:2021-08-09 16:58:00 來(lái)源:億速云 閱讀:177 作者:Leah 欄目:編程語(yǔ)言

PyQt5中如何使用QThread多線程模塊,相信很多沒(méi)有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問(wèn)題出現(xiàn)的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。

PyQt程序卡頓和無(wú)法實(shí)時(shí)顯示問(wèn)題現(xiàn)象

使用PyQt界面程序,點(diǎn)擊運(yùn)行按鈕后,程序在顯示框中每秒打印1個(gè)數(shù)字。程序代碼如下:

# -*- coding: utf-8 -*-import sysimport timefrom PyQt5.QtCore import QThread, pyqtSignalfrom PyQt5.QtWidgets import QApplication, QMainWindowfrom QThread_Example_UI import Ui_Formclass MyMainForm(QMainWindow, Ui_Form):  def __init__(self, parent=None):    super(MyMainForm, self).__init__(parent)    self.setupUi(self)    self.runButton.clicked.connect(self.display)  def display(self):    for i in range(20):      time.sleep(1)      self.listWidget.addItem(str(i))if __name__ == "__main__":  app = QApplication(sys.argv)  myWin = MyMainForm()  myWin.show()  sys.exit(app.exec_())

程序運(yùn)行過(guò)程結(jié)果如下(點(diǎn)擊Run按鈕后界面出現(xiàn) 未響應(yīng) 字樣 , 同時(shí)程序也沒(méi)有出現(xiàn)每隔1秒打印1個(gè)數(shù)字,實(shí)際結(jié)果是循環(huán)結(jié)束后20個(gè)數(shù)字一同展示):

問(wèn)題分析

上述實(shí)現(xiàn)的GUI程序都是單線程運(yùn)行,對(duì)于需要執(zhí)行一個(gè)特別耗時(shí)的操作時(shí)就會(huì)出現(xiàn)該問(wèn)題現(xiàn)象。要解決這種問(wèn)題可以考慮使用多線程模塊QThread。

多線程模塊QThread基本原理

QThread是Qt的線程類(lèi)中最核心的底層類(lèi)。由于PyQt的的跨平臺(tái)特性,QThread要隱藏所有與平臺(tái)相關(guān)的代碼要使用的QThread開(kāi)始一個(gè)線程,可以創(chuàng)建它的一個(gè)子類(lèi),然后覆蓋其它QThread.run()函數(shù)。

class Thread(QThread):  def __init__(self):    super(Thread,self).__init__()  def run(self):    #

接下來(lái)創(chuàng)建一個(gè)新的線程

thread = Thread()thread.start()

可以看出,PyQt的線程使用非常簡(jiǎn)單,建立一個(gè)自定義的類(lèi)(如Thread),自我繼承自QThread ,并實(shí)現(xiàn)其run()方法即可。在使用線程時(shí)可以直接得到Thread實(shí)例,調(diào)用其start()函數(shù)即可啟動(dòng)線程,線程啟動(dòng)之后,會(huì)自動(dòng)調(diào)用其實(shí)現(xiàn)的run()的函數(shù),該方法就是線程的執(zhí)行函數(shù) 。

業(yè)務(wù)的線程任務(wù)就寫(xiě)在run()函數(shù)中,當(dāng)run()退出之后線程就基本結(jié)束了,QThread有started和finished信號(hào),可以為這兩個(gè)信號(hào)指定槽函數(shù),在線程啟動(dòng)和結(jié)束之時(shí)執(zhí)行一段代碼進(jìn)行資源的初始化和釋放操作,更靈活的使用方法是,在自定義的QThread實(shí)例中自定義信號(hào),并將信號(hào)連接到指定的槽函數(shù),當(dāng)滿足一定的業(yè)務(wù)條件時(shí)發(fā)射此信號(hào)。

QThread類(lèi)中的常用方法

start():?jiǎn)?dòng)線程

wait():阻止線程,直到滿足如下條件之一

(1)與此QThread對(duì)象關(guān)聯(lián)的線程已完成執(zhí)行(即從run返回時(shí)),如果線程完成執(zhí)行,此函數(shù)返回True,如果線程尚未啟動(dòng),也返回True

(2)等待時(shí)間的單位是毫秒,如果時(shí)間是ULONG_MAX(默認(rèn)值·),則等待,永遠(yuǎn)不會(huì)超時(shí)(線程必須從run返回),如果等待超時(shí),此函數(shù)將會(huì)返回False

sleep():強(qiáng)制當(dāng)前線程睡眠多少秒

QThread類(lèi)中的常用信號(hào)

started: 在開(kāi)始執(zhí)行run函數(shù)之前,從相關(guān)線程發(fā)射此信號(hào)

finished:當(dāng)程序完成業(yè)務(wù)邏輯時(shí),從相關(guān)線程發(fā)射此信號(hào)

使用QThread重新實(shí)現(xiàn)程序解決問(wèn)題

先繼承QThread類(lèi)并重新實(shí)現(xiàn)其中的run()函數(shù),也就是說(shuō)把耗時(shí)的操作放入run()函數(shù)中。代碼如下:

# -*- coding: utf-8 -*-import sysimport timefrom PyQt5.QtCore import QThread, pyqtSignalfrom PyQt5.QtWidgets import QApplication, QMainWindowfrom QThread_Example_UI import Ui_Formclass MyMainForm(QMainWindow, Ui_Form):  def __init__(self, parent=None):    super(MyMainForm, self).__init__(parent)    self.setupUi(self)    # 實(shí)例化線程對(duì)象    self.work = WorkThread()    self.runButton.clicked.connect(self.execute)  def execute(self):    # 啟動(dòng)線程    self.work.start()    # 線程自定義信號(hào)連接的槽函數(shù)    self.work.trigger.connect(self.display)  def display(self,str):    # 由于自定義信號(hào)時(shí)自動(dòng)傳遞一個(gè)字符串參數(shù),所以在這個(gè)槽函數(shù)中要接受一個(gè)參數(shù)    self.listWidget.addItem(str)class WorkThread(QThread):  # 自定義信號(hào)對(duì)象。參數(shù)str就代表這個(gè)信號(hào)可以傳一個(gè)字符串  trigger = pyqtSignal(str)  def __int__(self):    # 初始化函數(shù)    super(WorkThread, self).__init__()  def run(self):    #重寫(xiě)線程執(zhí)行的run函數(shù)    #觸發(fā)自定義信號(hào)    for i in range(20):      time.sleep(1)      # 通過(guò)自定義信號(hào)把待顯示的字符串傳遞給槽函數(shù)      self.trigger.emit(str(i))if __name__ == "__main__":  app = QApplication(sys.argv)  myWin = MyMainForm()  myWin.show()  sys.exit(app.exec_())

程序運(yùn)行結(jié)果如下(實(shí)現(xiàn)了每隔1秒打印1個(gè)數(shù)字):

小結(jié)

如果你實(shí)現(xiàn)的工具需要執(zhí)行特別耗時(shí)的操作,可以參考使用本文多線程QThread處理方法實(shí)現(xiàn)。當(dāng)然,工具實(shí)際實(shí)現(xiàn)過(guò)程中的場(chǎng)景會(huì)比這復(fù)雜。比如,你的輸出并不是有固定時(shí)間間隔輸出的文本框,可以嘗試使用多次self.trigger.emit(str)方法進(jìn)行操作。

附錄

1、使用pyuic5轉(zhuǎn)換界面.ui程序后的QThread_Example_UI.py代碼如下:

# -*- coding: utf-8 -*-from PyQt5 import QtCore, QtGui, QtWidgetsclass Ui_Form(object):  def setupUi(self, Form):    Form.setObjectName("Form")    Form.resize(498, 331)    self.runButton = QtWidgets.QPushButton(Form)    self.runButton.setGeometry(QtCore.QRect(190, 30, 75, 23))    self.runButton.setObjectName("runButton")    self.listWidget = QtWidgets.QListWidget(Form)    self.listWidget.setGeometry(QtCore.QRect(30, 70, 431, 192))    self.listWidget.setObjectName("listWidget")    self.retranslateUi(Form)    QtCore.QMetaObject.connectSlotsByName(Form)  def retranslateUi(self, Form):    _translate = QtCore.QCoreApplication.translate    Form.setWindowTitle(_translate("Form", "Qthread Example"))    self.runButton.setText(_translate("Form", "Run"))

2、Qtdesigner設(shè)計(jì)的界面源程序代碼QThread_Example_UI.ui如下:

<?xml version="1.0" encoding="UTF-8"?><ui version="4.0"> <class>Form</class> <widget class="QWidget" name="Form"> <property name="geometry">  <rect>  <x>0</x>  <y>0</y>  <width>498</width>  <height>331</height>  </rect> </property> <property name="windowTitle">  <string>Qthread Example</string> </property> <widget class="QPushButton" name="runButton">  <property name="geometry">  <rect>   <x>190</x>   <y>30</y>   <width>75</width>   <height>23</height>  </rect>  </property>  <property name="text">  <string>Run</string>  </property> </widget> <widget class="QListWidget" name="listWidget">  <property name="geometry">  <rect>   <x>30</x>   <y>70</y>   <width>431</width>   <height>192</height>  </rect>  </property> </widget> </widget> <resources/> <connections/></ui>

看完上述內(nèi)容,你們掌握PyQt5中如何使用QThread多線程模塊的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI