【问题标题】:Thread Finished Event in PythonPython中的线程完成事件
【发布时间】:2009-05-01 19:27:20
【问题描述】:

我有一个 PyQt 程序,在这个程序中我启动了一个新线程来绘制一个复杂的图像。 我想知道线程何时结束,以便在表单上打印图像。

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

我可以使用一个线程来完成,但程序会停止。

我曾经在 C# 中使用具有完成事件的 BackgroundWorker 来执行此操作。

有没有办法在 Python 中做这样的事情?还是我应该侵入 PyQt 应用程序的主循环并对其进行一些更改?

【问题讨论】:

    标签: python delegates multithreading


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

      请注意,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"))
      

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          【解决方案4】:

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-12-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多