Discussione Evento finito in Python
-
03-07-2019 - |
Domanda
Ho un programma PyQt, in questo programma inizio un nuovo thread per disegnare un'immagine complicata. Voglio sapere quando il thread è terminato in modo da poter stampare l'immagine sul modulo.
L'unico ostacolo che sto affrontando è che devo invocare il metodo di disegno dall'interno del thread della GUI, quindi voglio un modo per dire al thread della GUI di fare qualcosa dall'interno del thread del disegno.
Potrei farlo usando un thread ma il programma si interrompe.
Lo facevo in C # usando un BackgroundWorker che aveva un evento per finire.
C'è un modo per fare una cosa del genere in Python? o dovrei hackerare il ciclo principale dell'applicazione PyQt e cambiarlo un po '?
Soluzione
Negli esempi con PyQt-Py2.6-gpl-4.4.4-2 .exe , c'è l'app Mandelbrot. Nella mia installazione, l'origine è in C: \ Python26 \ Lib \ site-pacchetti \ PyQt4 \ esempi \ thread \ mandelbrot.pyw. Usa un thread per rendere la pixmap e un segnale (cerca nel codice QtCore.SIGNAL) per dire al thread della GUI che è il momento di disegnare. Sembra quello che vuoi.
Altri suggerimenti
Ho avuto un problema simile con uno dei miei progetti e ho usato i segnali per dire al mio thread GUI principale quando visualizzare i risultati del lavoratore e aggiornare una barra di avanzamento.
Nota che ci sono diversi esempi per connettere oggetti e segnali nel guida di riferimento di PyQt . Non tutti si applicano a Python (mi ci è voluto un po 'per realizzarlo).
Ecco gli esempi che si desidera esaminare per collegare un segnale Python a una funzione Python.
QtCore.QObject.connect(a, QtCore.SIGNAL("PySig"), pyFunction)
a.emit(QtCore.SIGNAL("pySig"), "Hello", "World")
Inoltre, non dimenticare di aggiungere __pyqtSignals__ = (" PySig " ;,)
alla tua classe lavoratrice.
Ecco una versione ridotta di quello che ho fatto:
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"))
Credo che il tuo thread di disegno possa inviare un evento al thread principale usando QApplication.postEvent. Devi solo scegliere un oggetto come destinatario dell'evento. Ulteriori informazioni
Ampliamento della risposta di Jeff: la Qt documentazione su thread support afferma che è possibile far eseguire i gestori di eventi (slot in Qt parlance) nel thread che "possiede" un oggetto.
Quindi, nel tuo caso, dovresti definire uno slot printImage (QImage) sul modulo e un segnale doneDrawing (QImage) su qualunque cosa stia creando l'immagine, e collegarli semplicemente usando una coda o una connessione automatica.