J'essaye de mettre à jour un QProgressBar de pyqt à partir de plusieurs threads, et d'après ce que je comprends, la meilleure façon d'y parvenir est d'émettre des signaux dans le thread graphique principal (j'ai essayé de passer l'objet QProgressBar aux fils de travail et bien que cela semble fonctionner, j'ai reçu une tonne d'avertissements dans l'interprète). Dans le code suivant, j'ai mis en place un signal progressSignal et je l'ai connecté à un thread qui (pour l'instant) imprime tout ce qui a été émis. J'émets ensuite de chaque fil le pourcentage total. Je sais que cela fonctionne en dehors des threads en jetant juste une émission aléatoire dans la ligne 47, qui vient à travers. Cependant, la ligne 36 Emettre à partir ne déclenche rien, il ne semble jamais le faire par ...pyqt émet un signal à partir du thread de thread
import Queue, threading
from PyQt4 import QtCore
import shutil
import profile
fileQueue = Queue.Queue()
class Communicate(QtCore.QObject):
progressSignal = QtCore.pyqtSignal(int)
class ThreadedCopy:
totalFiles = 0
copyCount = 0
lock = threading.Lock()
def __init__(self, inputList, progressBar="Undefined"):
self.totalFiles = len(inputList)
self.c = Communicate()
self.c.progressSignal.connect(self.updateProgressBar)
print str(self.totalFiles) + " files to copy."
self.threadWorkerCopy(inputList)
def CopyWorker(self):
while True:
self.c.progressSignal.emit(2000)
fileName = fileQueue.get()
shutil.copy(fileName[0], fileName[1])
fileQueue.task_done()
with self.lock:
self.copyCount += 1
percent = (self.copyCount * 100)/self.totalFiles
self.c.progressSignal.emit(percent)
def threadWorkerCopy(self, fileNameList):
for i in range(16):
t = threading.Thread(target=self.CopyWorker)
t.daemon = True
t.start()
for fileName in fileNameList:
fileQueue.put(fileName)
fileQueue.join()
self.c.progressSignal.emit(1000)
def updateProgressBar(self, percent):
print percent
MISE À JOUR:
Heres un échantillon avec une interface utilisateur graphique. Celui-ci fonctionne, mais est assez instable, il se bloque régulièrement et l'interface utilisateur fait des trucs bizarres (barre de progression ne pas terminer, etc.)
Main.py:
import sys, os
import MultithreadedCopy_5
from PyQt4 import QtCore, QtGui
def grabFiles(path):
# gets all files (not folders) in a directory
for file in os.listdir(path):
if os.path.isfile(os.path.join(path, file)):
yield os.path.join(path, file)
class MainWin(QtGui.QWidget):
def __init__(self):
super(MainWin, self).__init__()
self.initUI()
def initUI(self):
self.progress = QtGui.QProgressBar()
box = QtGui.QVBoxLayout()
box.addWidget(self.progress)
goBtn = QtGui.QPushButton("Start copy")
box.addWidget(goBtn)
self.setLayout(box)
goBtn.clicked.connect(self.startCopy)
def startCopy(self):
files = grabFiles("folder/with/files")
fileList = []
for file in files:
fileList.append([file,"folder/to/copy/to"])
MultithreadedCopy_5.ThreadedCopy(fileList, self.progress)
def main():
app = QtGui.QApplication(sys.argv)
ex = MainWin()
ex.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
MultithreadedCopy_5.py:
import Queue, threading
from PyQt4 import QtCore
import shutil
import profile
fileQueue = Queue.Queue()
class Communicate(QtCore.QObject):
progressSignal = QtCore.pyqtSignal(int)
class ThreadedCopy:
totalFiles = 0
copyCount = 0
lock = threading.Lock()
def __init__(self, inputList, progressBar="Undefined"):
self.progressBar = progressBar
self.totalFiles = len(inputList)
self.c = Communicate()
self.c.progressSignal.connect(self.updateProgressBar, QtCore.Qt.DirectConnection)
print str(self.totalFiles) + " files to copy."
self.threadWorkerCopy(inputList)
def CopyWorker(self):
while True:
fileName = fileQueue.get()
shutil.copy(fileName[0], fileName[1])
fileQueue.task_done()
with self.lock:
self.copyCount += 1
percent = (self.copyCount * 100)/self.totalFiles
self.c.progressSignal.emit(percent)
def threadWorkerCopy(self, fileNameList):
for i in range(16):
t = threading.Thread(target=self.CopyWorker)
t.daemon = True
t.start()
for fileName in fileNameList:
fileQueue.put(fileName)
fileQueue.join()
def updateProgressBar(self, percent):
self.progressBar.setValue(percent)
#profile.run('ThreadedCopy()')
Je commence à réaliser que les fils de python ne peut pas émettre des signaux à la principale application de PyQt, de sorte que la façon de le faire « correcte » serait avec PyQt qthreads - que je préférerais ne pas faire. Y aurait-il un moyen facile d'émettre le signal dans le thread principal chaque fois qu'un thread de travail se termine? – Spencer
S'il vous plaît voir ma réponse pour une solution qui devrait au moins résoudre les problèmes avec les exemples indiqués dans votre question. – ekhumoro