Fil de discussion sur l'événement en Python
-
03-07-2019 - |
Question
J'ai un programme PyQt. Dans ce programme, je démarre un nouveau fil pour dessiner une image compliquée. Je veux savoir quand le fil est fini pour pouvoir imprimer l'image sur le formulaire.
Le seul obstacle auquel je suis confronté est la nécessité d'invoquer la méthode de dessin à l'intérieur du fil de l'interface graphique. Je souhaite donc un moyen d'indiquer au fil de l'interface graphique de faire quelque chose à partir du fil de dessin.
Je pouvais le faire en utilisant un seul thread, mais le programme s'arrête.
J'avais l'habitude de le faire en C # avec un BackgroundWorker qui avait un événement à terminer.
Y at-il un moyen de faire une telle chose en Python? ou devrais-je pirater la boucle principale de l'application PyQt et la changer un peu?
La solution
Dans les exemples avec PyQt-Py2.6-gpl-4.4.4-2 .exe , il y a l'application Mandelbrot. Dans mon installation, la source est dans C: \ Python26 \ Lib \ site-packages \ PyQt4 \ examples \ threads \ mandelbrot.pyw. Il utilise un fil pour restituer le pixmap et un signal (recherchez le code pour QtCore.SIGNAL) pour indiquer au thread de l'interface graphique qu'il est temps de dessiner. On dirait ce que tu veux.
Autres conseils
J'ai eu un problème similaire avec l'un de mes projets et j'ai utilisé des signaux pour indiquer à mon thread principal de l'interface graphique quand afficher les résultats de l'agent et mettre à jour une barre de progression.
Notez qu'il existe plusieurs exemples de connexion d'objets et de signaux dans le Guide de référence PyQt . Tous ne s’appliquent pas au python (cela m’a pris un certain temps pour le comprendre).
Voici les exemples que vous souhaitez examiner pour connecter un signal python à une fonction python.
QtCore.QObject.connect(a, QtCore.SIGNAL("PySig"), pyFunction)
a.emit(QtCore.SIGNAL("pySig"), "Hello", "World")
N'oubliez pas non plus d'ajouter __ pyqtSignals__ = ("PySig",)
à votre classe de travailleurs.
Voici une version simplifiée de ce que j'ai fait:
class MyGui(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.worker = None
def makeWorker(self):
#create new thread
self.worker = Worker(work_to_do)
#connect thread to GUI function
QtCore.QObject.connect(self.worker, QtCore.SIGNAL('progressUpdated'), self.updateWorkerProgress)
QtCore.QObject.connect(self.worker, QtCore.SIGNAL('resultsReady'), self.updateResults)
#start thread
self.worker.start()
def updateResults(self):
results = self.worker.results
#display results in the GUI
def updateWorkerProgress(self, msg)
progress = self.worker.progress
#update progress bar and display msg in status bar
class Worker(QtCore.QThread):
__pyqtSignals__ = ( "resultsReady",
"progressUpdated" )
def __init__(self, work_queue):
self.progress = 0
self.results = []
self.work_queue = work_queue
QtCore.QThread.__init__(self, None)
def run(self):
#do whatever work
num_work_items = len(self.work_queue)
for i, work_item in enumerate(self.work_queue):
new_progress = int((float(i)/num_work_items)*100)
#emit signal only if progress has changed
if self.progress != new_progress:
self.progress = new_progress
self.emit(QtCore.SIGNAL("progressUpdated"), 'Working...')
#process work item and update results
result = processWorkItem(work_item)
self.results.append(result)
self.emit(QtCore.SIGNAL("resultsReady"))
Je pense que votre thread de dessin peut envoyer un événement au thread principal à l'aide de QApplication.postEvent. Il vous suffit de choisir un objet en tant que destinataire de l'événement. Plus d'informations
Développement de la réponse de Jeff: Documentation Qt sur prise en charge des threads indique qu'il est possible de faire en sorte que les gestionnaires d'événements (slots au format Qt) s'exécutent dans le thread que "possède" " un objet.
Donc, dans votre cas, vous définiriez une fente printImage (QImage) sur le formulaire et un signal doneDrawing (QImage) sur tout ce qui crée l'image, et vous ne feriez que les connecter à l'aide d'une connexion en file d'attente ou automatique.