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

PyQt子線(xiàn)程處理業(yè)務(wù)事件的問(wèn)題解決

 更新時(shí)間:2024年02月07日 09:42:38   作者:阮靚仔  
在PyQt中,主線(xiàn)程通常是指GUI主循環(huán)所在的線(xiàn)程,而子線(xiàn)程則是執(zhí)行實(shí)際工作的線(xiàn)程,本文主要介紹了PyQt子線(xiàn)程處理業(yè)務(wù)事件的問(wèn)題解決,具有一定的參考價(jià)值,感興趣的可以了解一下

在PyQt中是不推薦使用UI主線(xiàn)程來(lái)處理耗時(shí)操作的,會(huì)造成窗口組件阻塞。耗時(shí)操作一般放在子線(xiàn)程中。子線(xiàn)程處理完成后,可能需要更新窗口組件,但是PyQt不推薦使用子線(xiàn)程來(lái)更新主線(xiàn)程(也不是不能更新),這就用到了信號(hào)槽機(jī)制來(lái)更新主線(xiàn)程。

  • 在QObject的一個(gè)子類(lèi)中創(chuàng)建一個(gè)信號(hào)(PyQt5.QtCore.pyqtSignal)屬性
  • 將這個(gè)信號(hào)屬性和其他類(lèi)中的函數(shù)綁定,綁定的這個(gè)函數(shù)叫做整個(gè)信號(hào)的槽函數(shù)。一個(gè)信號(hào)可以和多個(gè)槽函數(shù)綁定。
  • 該信號(hào)發(fā)出時(shí),就會(huì)調(diào)用對(duì)應(yīng)的槽函數(shù)

可能會(huì)有疑問(wèn),槽函數(shù)被執(zhí)行時(shí)所在的線(xiàn)程和發(fā)送信號(hào)的線(xiàn)程是不是同一個(gè)?

需要注意,信號(hào)一定義在QObject或其子類(lèi)中。調(diào)用該屬性的emit方法發(fā)出信號(hào)后,和該信號(hào)綁定的槽函數(shù)都將要被調(diào)用,但是調(diào)用的線(xiàn)程并不一定是發(fā)送信號(hào)的這個(gè)線(xiàn)程,這和PyQt中的線(xiàn)程親和性(Thread Affinity)有關(guān)。

線(xiàn)程親和性(Thread Affinity)

在 PyQt 中,一個(gè)對(duì)象可以被移動(dòng)到不同的線(xiàn)程中,但一個(gè)對(duì)象在同一時(shí)刻只能屬于一個(gè)線(xiàn)程。這是因?yàn)?Qt 使用線(xiàn)程親和性(Thread Affinity)的概念來(lái)管理對(duì)象所屬的線(xiàn)程。

每個(gè) Qt 對(duì)象都與一個(gè)特定的線(xiàn)程相關(guān)聯(lián),即它的線(xiàn)程親和性。對(duì)象的線(xiàn)程親和性決定了該對(duì)象的槽函數(shù)是在哪個(gè)線(xiàn)程中執(zhí)行。默認(rèn)情況下,對(duì)象在創(chuàng)建時(shí)會(huì)與創(chuàng)建它的線(xiàn)程相關(guān)聯(lián),但可以使用 moveToThread 方法將對(duì)象移動(dòng)到另一個(gè)線(xiàn)程中。

錯(cuò)誤示例:

from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton,QFileDialog
from PyQt5.QtCore import QThread,pyqtSignal,QObject
import sys, threading

class MyWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MyWindow, self).__init__(parent)
        self.button = QPushButton('Hi')
        self.button.clicked.connect(self.on_click)
        self.setCentralWidget(self.button)

    def on_click(self):
        print("on_click",threading.current_thread().name)
        self.thread = MyThread(self)
        self.thread.start()

    def set_text(self,file_name):
        print("setText",threading.current_thread().name)
        self.button.setText(file_name)

class MyThread(QThread):

    def __init__(self,mv:QMainWindow) -> None:
        super().__init__(None)
        self.mv = mv
        
    def run(self):
        print('run',threading.current_thread().name)
        QThread.sleep(5)
        self.mv.set_text("Hello World")

if __name__ == '__main__':
    app = QApplication([])
    window = MyWindow()
    window.show()
    sys.exit(app.exec_())

輸出結(jié)果:

on_click MainThread
run Dummy-1
setText Dummy-1   //子線(xiàn)程更新UI,不推薦

使用信號(hào)槽機(jī)制

from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton,QFileDialog
from PyQt5.QtCore import QThread,pyqtSignal,QObject
import sys, threading
class MyWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MyWindow, self).__init__(parent)
        self.button = QPushButton('Hi')
        self.button.clicked.connect(self.on_click)
        self.setCentralWidget(self.button)

    def on_click(self):
        print("on_click",threading.current_thread().name)
        self.thread = MyThread(self)
        self.thread.pyqtSignal.connect(self.set_text)
        self.thread.start()

    def set_text(self,file_name):
        print("setText",threading.current_thread().name)
        self.button.setText(file_name)

class MyThread(QThread):
    pyqtSignal =  pyqtSignal(str)
    def __init__(self,mv:QMainWindow) -> None:
        super().__init__(None)
        self.mv = mv

    def run(self):
        print('run',threading.current_thread().name)
        QThread.sleep(5)
        self.pyqtSignal.emit("Hello World")

if __name__ == '__main__':
    app = QApplication([])
    window = MyWindow()
    window.show()
    sys.exit(app.exec_())

輸出結(jié)果:

on_click MainThread
run Dummy-1
setText MainThread //更新UI時(shí),執(zhí)行的線(xiàn)程為主線(xiàn)程

setText槽函數(shù)為什么會(huì)被主函數(shù)執(zhí)行,就是因?yàn)榫€(xiàn)程親和性,槽函數(shù)所在對(duì)象和MainThread綁定,當(dāng)然會(huì)被主線(xiàn)程所執(zhí)行。

但是這種將事務(wù)直接寫(xiě)在run,PyQt5是不推薦的,正確寫(xiě)法如下

創(chuàng)建一個(gè)類(lèi)集成QObject,來(lái)做業(yè)務(wù)的處理。并將這個(gè)對(duì)象和新創(chuàng)建的線(xiàn)程通過(guò)moveToThread綁定,作為這個(gè)對(duì)象的親和線(xiàn)程。將QThread的started信號(hào)和這個(gè)業(yè)務(wù)事件綁定。線(xiàn)程啟動(dòng),發(fā)送started信號(hào),業(yè)務(wù)對(duì)象開(kāi)始處理業(yè)務(wù),完成之后發(fā)送信號(hào)給主線(xiàn)程槽函數(shù)。

from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton,QFileDialog
from PyQt5.QtCore import QThread,pyqtSignal,QObject
import sys, threading
class MyWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MyWindow, self).__init__(parent)
        self.button = QPushButton('Hi')
        self.button.clicked.connect(self.on_click)
        self.setCentralWidget(self.button)

    def on_click(self):
        print("on_click",threading.current_thread().name)
        self.thread = QThread()

        self.myHander = MyHandler()
        self.myHander.moveToThread(self.thread)
        self.myHander.pyqtSignal.connect(self.set_text)

        self.thread.started.connect(self.myHander.handle)
        self.thread.start()

    def set_text(self,file_name):
        print("setText",threading.current_thread().name)
        self.button.setText(file_name)
class MyHandler(QObject):
    pyqtSignal =  pyqtSignal(str)
    def handle(self):
        print('handle',threading.current_thread().name)
        self.pyqtSignal.emit("Hello World")


if __name__ == '__main__':
    app = QApplication([])
    window = MyWindow()
    window.show()
    sys.exit(app.exec_())

子線(xiàn)程中調(diào)用QFileDialog

如果在子線(xiàn)程中調(diào)用了QFileDialog窗口選擇文件,QFileDialog窗口出現(xiàn)后幾秒后程序會(huì)崩潰,代碼如下

from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton,QFileDialog
from PyQt5.QtCore import QThread,pyqtSignal,QObject
import sys, threading
class MyWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MyWindow, self).__init__(parent)
        self.button = QPushButton('Hi')
        self.button.clicked.connect(self.on_click)
        self.setCentralWidget(self.button)

    def on_click(self):
        print("on_click",threading.current_thread().name)
        self.thread = MyThread(self)
        self.thread.pyqtSignal.connect(self.set_text)
        self.thread.start()

    def set_text(self,file_name):
        print("setText",threading.current_thread().name)
        self.button.setText(file_name)

class MyThread(QThread):
    pyqtSignal =  pyqtSignal(str)
    def __init__(self,mv:QMainWindow) -> None:
        super().__init__(None)
        self.mv = mv

    def run(self):
        print('run',threading.current_thread().name)
        file_name = QFileDialog.getOpenFileName(self.mv, '選擇文件', './', 'Excel files(*.xlsx , *.xls)')
        print(file_name)
        self.pyqtSignal.emit("Hello World")

if __name__ == '__main__':
    app = QApplication([])
    window = MyWindow()
    window.show()
    sys.exit(app.exec_())


輸出結(jié)果:

on_click MainThread
run Dummy-1
QObject::setParent: Cannot set parent, new parent is in a different thread
CoCreateInstance failed (操作成功完成。)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QApplication(0x21fb451d190), parent's thread is QThread(0x21fb443b430), current thread is MyThread(0x21fb8788df0)
CoCreateInstance failed (操作成功完成。)
QObject::startTimer: Timers cannot be started from another thread

問(wèn)題原因

PyQt中,必須在主線(xiàn)程中來(lái)創(chuàng)建子對(duì)象。

到此這篇關(guān)于PyQt子線(xiàn)程處理業(yè)務(wù)事件的問(wèn)題解決的文章就介紹到這了,更多相關(guān)PyQt子線(xiàn)程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于Python編寫(xiě)一個(gè)ISBN查詢(xún)工具

    基于Python編寫(xiě)一個(gè)ISBN查詢(xún)工具

    這篇文章主要為大家詳細(xì)介紹了如何利用Python編寫(xiě)一個(gè)簡(jiǎn)單的ISBN查詢(xún)工具,可以用于圖書(shū)管理、圖書(shū)銷(xiāo)售、圖書(shū)收集和閱讀等場(chǎng)景,需要的可以參考一下
    2023-05-05
  • Python開(kāi)發(fā)圍棋游戲的實(shí)例代碼(實(shí)現(xiàn)全部功能)

    Python開(kāi)發(fā)圍棋游戲的實(shí)例代碼(實(shí)現(xiàn)全部功能)

    圍棋是一種古老而復(fù)雜的策略棋類(lèi)游戲,起源于中國(guó),已有超過(guò)2500年的歷史,本文介紹了如何用Python開(kāi)發(fā)一個(gè)簡(jiǎn)單的圍棋游戲,實(shí)例代碼涵蓋了游戲的基本規(guī)則、界面設(shè)計(jì)、棋盤(pán)實(shí)現(xiàn)、棋子管理、游戲邏輯等多個(gè)方面,通過(guò)逐步實(shí)現(xiàn)落子、吃子、判斷勝負(fù)等功能
    2024-12-12
  • Python 開(kāi)發(fā)Activex組件方法

    Python 開(kāi)發(fā)Activex組件方法

    Python強(qiáng)的功能就在于它無(wú)所不能。
    2009-11-11
  • python實(shí)現(xiàn)異步回調(diào)機(jī)制代碼分享

    python實(shí)現(xiàn)異步回調(diào)機(jī)制代碼分享

    本文介紹了python實(shí)現(xiàn)異步回調(diào)機(jī)制的功能,大家參考使用吧
    2014-01-01
  • python Aligo庫(kù)設(shè)置json路徑使用詳解

    python Aligo庫(kù)設(shè)置json路徑使用詳解

    這篇文章主要為大家介紹了python Aligo庫(kù)設(shè)置json路徑使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • 下載官網(wǎng)python并安裝的步驟詳解

    下載官網(wǎng)python并安裝的步驟詳解

    在本篇文章里小編給大家整理了關(guān)于下載官網(wǎng)python并安裝的步驟詳解,需要的朋友們參考學(xué)習(xí)下。
    2019-10-10
  • 探索?Python?Restful?接口測(cè)試的奧秘

    探索?Python?Restful?接口測(cè)試的奧秘

    掌握Python?Restful?接口測(cè)試,讓你的后端服務(wù)像流水一樣順暢,本指南將帶你輕松穿梭于斷言和請(qǐng)求之間,搞定所有測(cè)試難題,一起來(lái)看,讓代碼在你的指尖跳舞吧!
    2023-12-12
  • pycharm如何關(guān)閉pytest

    pycharm如何關(guān)閉pytest

    這篇文章主要介紹了pycharm如何關(guān)閉pytest問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • python實(shí)現(xiàn)一個(gè)通用的插件類(lèi)

    python實(shí)現(xiàn)一個(gè)通用的插件類(lèi)

    插件管理器用于注冊(cè)、銷(xiāo)毀、執(zhí)行插件,本文主要介紹了python實(shí)現(xiàn)一個(gè)通用的插件類(lèi),文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-04-04
  • Python3爬蟲(chóng)中Splash的知識(shí)總結(jié)

    Python3爬蟲(chóng)中Splash的知識(shí)總結(jié)

    在本篇文章里小編給大家整理的是關(guān)于Python3爬蟲(chóng)中Splash的知識(shí)總結(jié)內(nèi)容,需要的朋友們可以學(xué)習(xí)參考下。
    2020-07-07

最新評(píng)論