Thread Finished Event in Python

匿名 (未验证) 提交于 2019-12-03 01:34:02

问题:

I have a PyQt program, in this program I start a new thread for drawing a complicated image. I want to know when the thread has finished so I can print the image on the form.

The only obstacle I'm facing is that I need to invoke the method of drawing from inside the GUI thread, so I want a way to tell the GUI thread to do something from inside the drawing thread.

I could do it using one thread but the program halts.

I used to do it in C# using a BackgroundWorker which had an event for finishing.

Is there a way to do such thing in Python? or should I hack into the main loop of PyQt application and change it a bit?

回答1:

In the samples with PyQt-Py2.6-gpl-4.4.4-2.exe, there's the Mandelbrot app. In my install, the source is in C:\Python26\Lib\site-packages\PyQt4\examples\threads\mandelbrot.pyw. It uses a thread to render the pixmap and a signal (search the code for QtCore.SIGNAL) to tell the GUI thread its time to draw. Looks like what you want.



回答2:

I had a similar issue with one of my projects, and used signals to tell my main GUI thread when to display results from the worker and update a progress bar.

Note that there are several examples to connect objects and signals in the PyQt reference guide. Not all of which apply to python (took me a while to realize this).

Here are the examples you want to look at for connecting a python signal to a python function.

QtCore.QObject.connect(a, QtCore.SIGNAL("PySig"), pyFunction) a.emit(QtCore.SIGNAL("pySig"), "Hello", "World") 

Also, don't forget to add __pyqtSignals__ = ( "PySig", ) to your worker class.

Here's a stripped down version of what I did:

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")) 


回答3:

I believe that your drawing thread can send an event to the main thread using QApplication.postEvent. You just need to pick some object as the receiver of the event. More info



回答4:

Expanding on Jeff's answer: the Qt documentation on thread support states that it's possible to make event handlers (slots in Qt parlance) execute in the thread that "owns" an object.

So in your case, you'd define a slot printImage(QImage) on the form, and a doneDrawing(QImage) signal on whatever is creating the image, and just connect them using a queued or auto connection.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!