簡體   English   中英

即使在 run() 完成后 QThread 也沒有發出信號

[英]QThread is not emitting signal even after run() finished

當用戶點擊“更新”按鈕時,box_updatetool_fcn 將被執行。 MainThread 將更新 QMainWindow 中的 Progressbar,而另一個 QThread 將下載文件。 但它執行完美,但問題是 WorkerThread 發出的信號沒有立即更新。

即使我經歷了很多問題,也沒有一個能解決我的問題。 我不知道為什么我的fcn_qthread_output在 Qthread 完成后沒有立即執行。

甚至 QThread finished() function 也在 Main Function 完成后執行,我在當前程序中沒有使用它。 我不知道程序有什么問題,是不是缺少什么?

這是以下控制台 output -

Run Function Closed 
Out1 : False, FileName 
Main Function Ended 
Out2 : True, FileName

我期待的是——

Run Function Closed 
Out2 : True, FileName 
Out1 : True, FileName
Main Function Ended 

下面是程序執行流程——

class WorkerThread(QtCore.QThread):
    outResult = QtCore.pyqtSignal(tuple)
    def __init__(self,target,args,parent=None):
        super(WorkerThread, self).__init__(parent)
        self.fcn  = target
        self.args = args
    
    def run(self):
        outResult = self.fcn(*self.args)
        self.outResult.emit(outResult)
        print('Run Function Closed')

class ApplicationWindow(QtWidgets.QMainWindow):
    def box_updatetool_fcn(self):
        t1 = WorkerThread(target=self.boxapi.fcn_downloadfile, args=(fileID,)) #ThreadWithResult
        t1.outResult.connect(self.fcn_qthread_output)
        t1.start()
        self.box_pbar_fcn(tempfilename,fsize)
        print(f'Out1 : {self.var_box_output}')
        self.boxapi.fcn_updatetool(file_fullpath,self.progpath)
        print('Main Function Ended')
    
    def fcn_qthread_output(self,result):
        self.var_box_output = result
        print(f'Out2 : {self.var_box_output}')

    def box_pbar_fcn(self,filename,fullsize):
        pobj = self.ui.progressbar
        while(barprogress < 100):
        if os.path.exists(filename):
            currfilesize = os.path.getsize(filename)
            barprogress  = int(currfilesize/fullsize*100)
            pobj.setValue(barprogress)

可重現的代碼 -

我使用了 box_pbar_fcn (顯示下載進度的進度條)和t1 線程(下載文件)將同時運行。

import os, sys
from PyQt5 import QtWidgets, QtGui, QtCore

class WorkerThread(QtCore.QThread):
    outResult = QtCore.pyqtSignal(tuple)
    def __init__(self,parent=None):
        super(WorkerThread, self).__init__(parent)

    def run(self):
        outResult = (True,'Out1')
        self.outResult.emit(outResult)
        print('Run Function Closed')

class ApplicationWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.var_box_output = (False,'Inp1')
        self.box_updatetool_fcn()
        
    def box_updatetool_fcn(self):
        tempfilename,fsize = 'Test',300
        t1 = WorkerThread() #ThreadWithResult
        t1.outResult.connect(self.fcn_qthread_output)
        t1.start()
        self.box_pbar_fcn(tempfilename,fsize)
        print(f'Out1 : {self.var_box_output}')
        print('Main Function Ended')
    
    def fcn_qthread_output(self,result):
        self.var_box_output = result
        print(f'Out2 : {self.var_box_output}')

    def box_pbar_fcn(self,filename,fullsize):
        pass
        #pobj = self.ui.progressbar
        #while(barprogress < 100):
        #if os.path.exists(filename):
        #   currfilesize = os.path.getsize(filename)
        #   barprogress  = int(currfilesize/fullsize*100)
        #   pobj.setValue(barprogress)

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    mw = ApplicationWindow()
    mw.show()
    sys.exit(app.exec_())

問題是你用你的 while True 阻塞了主線程(永遠不應該有一條指令長時間阻塞事件循環)。 在 Qt 中,邏輯是異步完成這項工作。 在這種情況下,我懷疑在一個線程中您正在下載文件並且您想在 QProgressBar 中顯示下載進度,為此您不斷測量文件的大小。 如果是這樣,一個可能的解決方案是使用 QTimer 來運行測量文件大小的周期性任務。

免責聲明:以下未經測試的代碼應該可以工作。 由於我不知道您保存文件的方式如何,因此它可能不起作用,因為許多函數只在最后寫入文件,而不是出於效率原因部分寫入文件。

import os
import sys
from functools import cached_property

from PyQt5 import QtCore, QtGui, QtWidgets


class Downloader(QtCore.QThread):
    outResult = QtCore.pyqtSignal(tuple)

    def run(self):
        import time

        time.sleep(10)
        outResult = (True, "Out1")
        self.outResult.emit(outResult)
        print("Run Function Closed")


class FileObserver(QtCore.QObject):
    def __init__(self, parent=None):
        super().__init__(parent)

        self._filename = ""
        self._current_size = 0

    @property
    def filename(self):
        return self._filename

    def start(self, filename, interval=100):
        self._current_size = 0
        self._filename = filename
        self.timer.setInterval(interval)
        self.timer.start()

    def stop(self):
        self.timer.stop()

    @cached_property
    def timer(self):
        timer = QtCore.QTimer()
        timer.timeout.connect(self._measure)
        return timer

    def _measure(self):
        if os.path.exists(self.filename):
            file_size = os.path.getsize(filename)
            if self._current_size != file_size:
                self._current_size = file_size
                self.file_size_changed.emit(file_size)


class ApplicationWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.var_box_output = (False, "Inp1")
        self.box_updatetool_fcn()

    @cached_property
    def file_observer(self):
        return FileObserver()

    def box_updatetool_fcn(self):
        tempfilename, fullsize = "Test", 300
        self.ui.progressbar.setMaximum(fullsize)

        t1 = WorkerThread(self)
        t1.outResult.connect(self.fcn_qthread_output)
        t1.finished.connect(self.file_observer.stop)
        t1.start()

        self.file_observer.start(tempfilename, interval=10)

    def fcn_qthread_output(self, result):
        self.var_box_output = result
        print(f"Out2 : {self.var_box_output}")

    def box_pbar_fcn(self, file_size):
        self.ui.progressbar.setValue(file_size)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    mw = ApplicationWindow()
    mw.show()
    sys.exit(app.exec_())

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM