Skip to content Skip to sidebar Skip to footer

Pyqt Emit Signal From Threading Thread

I'm trying to update a pyqt QProgressBar from multiple threads, and from what I understand the best way to do this is by emitting signals back to the main GUI thread (I tried passi

Solution 1:

There are two main problems with your examples.

Firstly, the object that emits the signals is created in the main/gui thread, so any signals its emits will not be cross-thread, and hence not thread-safe. The obvious solution to this is to create the signalling object inside the target function of the worker thread - which means there must be a separate instance for each thread.

Secondly, the while-loop inside the target function is never terminated, which means every ThreadedCopy object will be kept alive after the current copy operation is complete. Since all these objects share the same queue, the behaviour will become unpredictable if any attempt is made to repeat the copy operation. The obvious solution to this is to break out of the while-loop once the queue is empty.

Below is a re-write of MultithreadedCopy_5.py which should solve these issues. However, as stated in the comments, I would still strongly recommend using QThread rather than python threads in this scenario, as it is likely to provide a much more robust and more easily maintainable solution.

import Queue, threading
from PyQt4 import QtCore
import shutil
import profile

fileQueue = Queue.Queue()

classCommunicate(QtCore.QObject):
    progressSignal = QtCore.pyqtSignal(int)

classThreadedCopy:
    totalFiles = 0
    copyCount = 0
    lock = threading.Lock()

    def__init__(self, inputList, progressBar="Undefined"):
        self.progressBar = progressBar
        self.totalFiles = len(inputList)
        printstr(self.totalFiles) + " files to copy."
        self.threadWorkerCopy(inputList)

    defCopyWorker(self):
        c = Communicate()
        c.progressSignal.connect(self.updateProgressBar)
        whileTrue:
            try:
                fileName = fileQueue.get(False)
            except Queue.Empty:
                breakelse:
                shutil.copy(fileName[0], fileName[1])
                with self.lock:
                    self.copyCount += 1
                    percent = (self.copyCount * 100) / self.totalFiles
                    c.progressSignal.emit(percent)
                fileQueue.task_done()

    defthreadWorkerCopy(self, fileNameList):
        if fileQueue.empty():
            for i inrange(16):
                t = threading.Thread(target=self.CopyWorker)
                t.daemon = True
                t.start()
            for fileName in fileNameList:
                fileQueue.put(fileName)
            fileQueue.join()

    defupdateProgressBar(self, percent):
        self.progressBar.setValue(percent)

Solution 2:

The main problem is the delay of time between sending the signal and receiving, we can reduce that time using processEvents():

You can call this function occasionally when your program is busy performing a long operation (e.g. copying a file).

defCopyWorker(self):
    whileTrue:
        fileName = fileQueue.get()
        shutil.copy(fileName[0], fileName[1])
        fileQueue.task_done()
        with self.lock:
            self.copyCount += 1print(self.copyCount)
            percent = (self.copyCount * 100) / self.totalFiles
            self.c.progressSignal.emit(percent)
            QtCore.QCoreApplication.processEvents()

Post a Comment for "Pyqt Emit Signal From Threading Thread"