Python中的线程完成事件

时间:2009-05-01 19:27:21

标签: python delegates multithreading

我有一个PyQt程序,在这个程序中我开始绘制一个复杂图像的新线程。 我想知道线程何时完成,以便我可以在表单上打印图像。

我面临的唯一障碍是我需要从GUI线程内部调用绘图方法,所以我想要一种方法告诉GUI线程从绘图线程中做一些事情。

我可以使用一个线程但程序暂停。

我以前在C#中使用BackgroundWorker来完成它,后者有一个完成事件。

有没有办法在Python中做这样的事情?或者我应该入侵PyQt应用程序的主循环并稍微更改一下?

4 个答案:

答案 0 :(得分:2)

PyQt-Py2.6-gpl-4.4.4-2.exe的示例中,有Mandelbrot应用。在我的安装中,源代码位于C:\ Python26 \ Lib \ site-packages \ PyQt4 \ examples \ threads \ mandelbrot.pyw。它使用一个线程来渲染像素图和一个信号(搜索QtCore.SIGNAL的代码)来告诉GUI线程绘制它的时间。看起来像你想要的。

答案 1 :(得分:1)

我的一个项目遇到了类似的问题,并使用信号告诉我的主GUI线程何时显示来自worker的结果并更新进度条。

请注意,有几个示例可以在PyQt reference guide中连接对象和信号。并非所有这些都适用于python(花了一些时间才意识到这一点)。

以下是您希望将python信号连接到python函数的示例。

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

另外,不要忘记将__pyqtSignals__ = ( "PySig", )添加到您的工人类。

这是我所做的精简版:

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

答案 2 :(得分:0)

我相信您的绘图线程可以使用QApplication.postEvent将事件发送到主线程。您只需要选择一些对象作为事件的接收者。 More info

答案 3 :(得分:0)

扩展Jeff的答案:Qt documentation on thread support表示可以在“拥有”对象的线程中执行事件处理程序(Qt用语中的插槽)。

因此,在您的情况下,您将在窗体上定义一个插槽printImage(QImage),并在创建图像的任何内容上创建一个doneDrawing(QImage)信号,并使用排队或自动连接来连接它们。