欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

PyQt5執(zhí)行耗時操作導(dǎo)致界面卡死或未響應(yīng)的原因及解決辦法

 更新時間:2023年12月11日 16:19:51   作者:bill_love_c  
這篇文章主要給大家介紹了關(guān)于PyQt5執(zhí)行耗時操作導(dǎo)致界面卡死或未響應(yīng)的原因及解決辦法,由于耗時的操作會獨占系統(tǒng)cpu資源,讓界面卡死在那里,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

問題場景:

當用PyQt5開發(fā)一個GUI界面 ,需要執(zhí)行業(yè)務(wù)邏輯時,后臺邏輯執(zhí)行時間長,界面就容易出現(xiàn)卡死、未響應(yīng)等問題。

問題原因:

在PyQt中,GUI界面本身就是一個處理事件循環(huán)的主線程,當進行耗時操作時,主線程GUI需要等待操作完成后才會響應(yīng),在等待這段時間,整個GUI就處于卡死的狀態(tài)。在windows下,系統(tǒng)會認為這個程序運行出錯了,會自動顯示未響應(yīng),如果這時有其他的操作,整個程序就會卡死崩潰。

解決辦法:

另開一個線程來執(zhí)行這個耗時操作(使用QThread)

from PyQt5.QtCore import QThread

通過繼承QThread并重寫run()方法的方式實現(xiàn)多線程代碼的編寫。
結(jié)構(gòu)大體如下:

class Worker(QThread):
    def __init__(self):
        super().__init__()
    def run(self):
        --snip--

把耗時操作放到一個Worker線程中的run()函數(shù)下執(zhí)行,在GUI類文件中綁定操作的地方,創(chuàng)建Worker進程實例,啟動進程即可。

t = Worker()
t.start()

進階用法

上文中的方法開啟了一個新的線程去完成耗時操作;在GUI界面運行的過程中,常需要與新的線程之間保持信息的傳遞即“通信”,在pyqt5中這通過信號去實現(xiàn),這樣能保證GUI界面對后臺操作進行實時的響應(yīng),例如:按鈕狀態(tài)的更新、文字瀏覽窗口的消息變化、子窗口的打開及關(guān)閉等。

信號及自定義信號

在PyQt5中,信號與槽的使用有如下一些特點:

· 一個信號可以關(guān)聯(lián)多個槽函數(shù)。

· 一個信號也可以關(guān)聯(lián)其他信號。

· 信號的參數(shù)可以是任何Python數(shù)據(jù)類型。

· 一個槽函數(shù)可以和多個信號關(guān)聯(lián)。

· 關(guān)聯(lián)可以是直接的(同步)或排隊的(異步)。

· 可以在不同線程之間建立關(guān)聯(lián)。

· 信號與槽也可以斷開關(guān)聯(lián)。

在自定義類中還可以自定義信號。使用自定義信號在程序的對象之間傳遞信息是非常方便的,使用PyQt5.QtCore.pyqtSignal()為一個類定義新的信號。要自定義信號,類必須是QObject類的子類。pyqtSignal()的句法是:

        pyqtSignal(types[, name[, revision=0[, arguments=[]]]])

信號可以帶有參數(shù)types,后面的參數(shù)都是一些可選項,基本不使用。信號需要定義為類屬性,這樣定義的信號是未綁定(unbound)信號。當創(chuàng)建類的實例后,PyQt5會自動將類的實例與信號綁定,這樣就生成了綁定的(bound)信號。這與Python語言從類的函數(shù)生成綁定的方法的機制是一樣的。一個綁定的信號(也就是類的實例對象的信號)具有connect()、disconnect()和emit()這3個函數(shù),分別用于關(guān)聯(lián)槽函數(shù)、斷開與槽函數(shù)的關(guān)聯(lián)、發(fā)射信號。

使用示例

通過信號的emit()函數(shù)發(fā)射信號。在類的某個狀態(tài)發(fā)生變化,需要通知外部發(fā)生了這種變化時,發(fā)射相應(yīng)的信號。如果信號關(guān)聯(lián)了一個槽函數(shù),就會執(zhí)行槽函數(shù),如果信號沒有關(guān)聯(lián)槽函數(shù),就不會產(chǎn)生任何動作。

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'Qua_Ins.ui'
#
# Created by: PyQt5 UI code generator 5.15.4 @bill_love_3
import sys
import os
import time
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QObject
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *


class Worker(QThread, QObject):  # 自定義信號,執(zhí)行run()函數(shù)時,從線程發(fā)射此信號
    sinOut = pyqtSignal(str)
    sinEnd = pyqtSignal()

    def __init__(self, obj, parent=None):
        QThread.__init__(self, parent)
        QObject.__init__(self, parent)
        self.obj = obj

    def Threading_topo(self):  # CheckTopology子進程輸出讀取方法
         --snip-- # 耗時操作,約300S左右

    def run(self):
        self.sinOut.emit('...正在導(dǎo)入數(shù)據(jù)...')
        time.sleep(2)
        self.sinOut.emit('...開始檢查...')
        time.sleep(1)
        myQIns = QI(self.obj.filename)
        myQIns.line_lsit.append(os.path.basename(self.obj.filename) + '\n')
        # ---------------------開啟Check Topology子進程  ----------------------------------------------
        if self.obj.checkBox_Topology.isChecked():
            self.sinOut.emit('-----------------檢查中----請等待程序完成請勿關(guān)閉----\n')
            self.Threading_topo()
        myQIns.Complete_check()
        self.sinOut.emit('檢查完成。\n')
        time.sleep(2)
        myQIns.WriteTxt()
        self.sinOut.emit('報告生成中...\n')
        time.sleep(2)
        myQIns.CleanGdb()
        self.sinEnd.emit()

上面的片段就是一個完整的通過繼承QThread, QObject類生成的自定義類,由它開啟一個新的線程完成GUI程序中耗時的業(yè)務(wù)邏輯操作,保證GUI的主線程不會停下來等待,一直處于事件循環(huán)的狀態(tài)。在GUI的類文件中,通過調(diào)用產(chǎn)生該Worker()類的實例,在需要進行該操作的信號綁定處開啟線程。

class Ui_MainWindow():
    def __init__(self):
        self.filename = ''
        self.thread_btn_start = Worker(self, None)

這里將GUI的類創(chuàng)建的對象本身(self)作為obj參數(shù)傳遞到Worker()類中,可以看到Worker類中的self.obj.filename對應(yīng)GUI類中的self.filename;通過這種用法可以實現(xiàn)GUI主線程對Worker開啟的線程的信息傳遞,這種用法與類的嵌套中內(nèi)部類和外部類之間通信的方法是一致的。

    def pushButton_start_event(self):  # 檢查按鈕綁定事件
        if self.filename:
            self.thread_btn_start.sinOut.connect(self.text_browser_show)
            self.thread_btn_start.sinEnd.connect(self.set_pushButton)
            self.thread_btn_start.start()

這里設(shè)置Worker線程中sinOut、sinEnd信號綁定的槽函數(shù),之后開啟線程。

注意

不要嘗試在Worker開啟的線程中去設(shè)置GUI界面中的控件屬性,因為可能會導(dǎo)致未知的錯誤;pyqt最重要的特點信號和槽函數(shù)其中的一個用法就是用于各對象之間的信息傳遞,所以總是應(yīng)該用信號去傳遞信息,包括對其他控件的狀態(tài)修改等諸如此類的操作。

    def set_pushButton(self):
        self.pushButton_start.setEnabled(True)
        self.pushButton_chose.setEnabled(True)

這里通過thread_btn_start.sinEnd信號綁定的set_pushButton槽函數(shù)設(shè)置pushButton_start按鈕的狀態(tài)。

總結(jié)

通過自定義信號和繼承重寫QThread類的run()函數(shù)的方法可以很好的解決耗時操作導(dǎo)致界面卡死的問題。但也存在一些不足,比如增加額外的資源開銷、程序整體執(zhí)行時間變長了(變慢了);當然在更好的操作體驗面前這些都是可以忽略的,畢竟GUI(Graphical User Interface)的定義就是圖形用戶界面。

其他補充

應(yīng)該將信號綁定放在需要多次操作的函數(shù)外部,否則應(yīng)設(shè)置操作完成后的判斷條件去斷開信號綁定;不然會出現(xiàn)信號多次綁定到同一槽函數(shù),結(jié)果就是一次信號傳遞執(zhí)行兩次已綁定槽函數(shù)。

class Ui_MainWindow(object):

    def __init__(self):
        self.filename = ''
        self.thread_btn_start = Worker(self, None)
        self.thread_btn_start.sinOut.connect(self.text_browser_show)
        self.thread_btn_start.sinEnd.connect(self.set_pushButton)

    def pushButton_start_event(self):  # 檢查按鈕綁定事件
        if self.filename:
            self.pushButton_start.setEnabled(False)
            self.pushButton_chose.setEnabled(False)
            self.thread_btn_start.start()
            
    def set_pushButton(self):
        self.pushButton_start.setEnabled(True)
        self.pushButton_chose.setEnabled(True)

總結(jié) 

到此這篇關(guān)于PyQt5執(zhí)行耗時操作導(dǎo)致界面卡死或未響應(yīng)的原因及解決辦法的文章就介紹到這了,更多相關(guān)PyQt5執(zhí)行耗操作導(dǎo)致界面卡死內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python中擴展包的安裝方法詳解

    Python中擴展包的安裝方法詳解

    這篇文章主要給大家總結(jié)了關(guān)于Python中擴展包的安裝方法,文中介紹的非常詳細,對大家具有一定的參考學(xué)習(xí)價值,需要的朋友們下面跟著小編一起來學(xué)習(xí)學(xué)習(xí)吧。
    2017-06-06
  • Python配置pip國內(nèi)鏡像源的實現(xiàn)

    Python配置pip國內(nèi)鏡像源的實現(xiàn)

    這篇文章主要介紹了Python配置pip國內(nèi)鏡像源的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • python+mysql實現(xiàn)簡單的web程序

    python+mysql實現(xiàn)簡單的web程序

    上篇文章我們介紹了簡單的Python web程序,實現(xiàn)hello world,本文我們來結(jié)合一下mysql,實現(xiàn)對數(shù)據(jù)庫的簡單操作,希望對大家有所幫助
    2014-09-09
  • Python讀取圖像并顯示灰度圖的實現(xiàn)

    Python讀取圖像并顯示灰度圖的實現(xiàn)

    這篇文章主要介紹了Python讀取圖像并顯示灰度圖的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Python學(xué)習(xí)筆記之常用函數(shù)及說明

    Python學(xué)習(xí)筆記之常用函數(shù)及說明

    俗話說“好記性不如爛筆頭”,老祖宗們幾千年總結(jié)出來的東西還是有些道理的,所以,常用的東西也要記下來,不記不知道,一記嚇一跳,乖乖,函數(shù)咋這么多捏
    2014-05-05
  • calendar在python3時間中常用函數(shù)舉例詳解

    calendar在python3時間中常用函數(shù)舉例詳解

    這篇文章主要介紹了calendar在python3時間中常用函數(shù)的相關(guān)文章,對此知識點有興趣的朋友們可以學(xué)習(xí)下。
    2020-11-11
  • Python異步處理返回進度——使用Flask實現(xiàn)進度條

    Python異步處理返回進度——使用Flask實現(xiàn)進度條

    這篇文章主要介紹了Python異步處理返回進度——使用Flask實現(xiàn)進度條,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • Python實現(xiàn)基于socket的udp傳輸與接收功能詳解

    Python實現(xiàn)基于socket的udp傳輸與接收功能詳解

    這篇文章主要介紹了Python實現(xiàn)基于socket的udp傳輸與接收功能,結(jié)合實例形式詳細分析了Python使用socket進行udp文件傳輸與接收相關(guān)操作技巧及注意事項,需要的朋友可以參考下
    2019-11-11
  • 利用python實現(xiàn)凱撒密碼加解密功能

    利用python實現(xiàn)凱撒密碼加解密功能

    這篇文章主要介紹了利用python實現(xiàn)凱撒密碼加解密功能,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-03-03
  • Tensorflow2.1 完成權(quán)重或模型的保存和加載

    Tensorflow2.1 完成權(quán)重或模型的保存和加載

    這篇文章主要為大家介紹了Tensorflow2.1 完成權(quán)重或模型的保存和加載,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11

最新評論