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?

Était-ce utile?

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top