【问题标题】:Custom signals and multithreading自定义信号和多线程
【发布时间】:2016-05-06 16:58:45
【问题描述】:

我一直在努力使这段代码工作,但我仍然看不出缺陷在哪里。 我正在尝试从一个新线程发出信号,所以主线程接收信号并执行一个函数。

如果我尝试在同一个线程中执行此操作,一切正常 - 但使用此代码,线程已创建,但信号从未连接。

from PyQt4.QtCore import * 
from PyQt4.QtGui import *
from PyQt4 import QtCore

class WorkThread(QtCore.QThread):
    def __init__(self):
        QtCore.QThread.__init__(self)

    def run(self):
        print("From thread")
        self.emit(QtCore.SIGNAL("trying"))
        return

class Foo(QObject):            
    def handle_trigger(self):
        print ("trigger signal received")

    def new_thread(self):
        self.get_thread = WorkThread()
        self.connect(self.get_thread, QtCore.SIGNAL("trying"), self.handle_trigger)
        self.get_thread.start()


a = Foo()
a.new_thread()

【问题讨论】:

    标签: python multithreading pyqt signals-slots


    【解决方案1】:

    根据 cmets 编辑。

    您的代码存在一个主要问题。您实际上并没有启动 Qt 应用程序,因此没有运行主事件循环。您必须添加以下行:

    app = QApplication(sys.argv)
    app.exec_()
    

    此外,如果可能,您应该使用new-style Qt signals/slots,或者如果您坚持使用旧样式,请知道如果您还希望 Qt 信号也使用work with PySide,它应该采用 C 函数的形式。要将其更改为与 PySide 一起使用,它将是 QtCore.SIGNAL("trying()"),而不是 QtCore.SIGNAL("trying")。有关详细信息,请参阅 cmets(特别是我的和 @ekhumoro 的 cmets)。

    这是您的代码的工作版本(使用旧式信号/插槽),我尝试尽可能少地更改,以便您可以看到细微的变化。我不得不改用 PySide,但它也应该适用于 PyQt:

    from PySide.QtCore import * 
    from PySide.QtGui import *
    from PySide import QtCore
    import sys
    
    class WorkThread(QtCore.QThread):
        def __init__(self):
            QtCore.QThread.__init__(self)
    
        def run(self):
            print("From thread")
            self.emit(QtCore.SIGNAL("trying()"))
    
    class Foo(QObject):
        def handle_trigger(self):
            print ("trigger signal received")
            self.get_thread.quit()
            self.get_thread.wait()
            QApplication.quit()
    
        def new_thread(self):
            self.get_thread = WorkThread()
            self.connect(self.get_thread, QtCore.SIGNAL("trying()"), self.handle_trigger)
            self.get_thread.start()
    
    a = Foo()
    a.new_thread()
    
    app = QApplication(sys.argv)
    app.exec_()
    

    这是一个使用新信号/插槽样式的版本(请参阅@three_pineapples 评论)。这是在 PyQt/PySide 中实现信号/槽的推荐方式。

    from PySide.QtCore import * 
    from PySide.QtGui import *
    from PySide import QtCore
    import sys
    
    class WorkThread(QtCore.QThread):
        ranThread = QtCore.Signal()
        # for PyQt, use QtCore.pyqtSignal() instead
    
        def __init__(self):
            QtCore.QThread.__init__(self)
    
        def run(self):
            print("From thread")
            self.ranThread.emit()
    
    class Foo(QObject):
        def handle_trigger(self):
            print ("trigger signal received")
            self.get_thread.quit()
            self.get_thread.wait()
            QApplication.quit()
    
        def new_thread(self):
            self.get_thread = WorkThread()
            self.get_thread.ranThread.connect(self.handle_trigger)
            self.get_thread.start()
    
    a = Foo()
    a.new_thread()
    
    app = QApplication(sys.argv)
    app.exec_()
    

    【讨论】:

    • 为避免以后出现此类错误,最好还是切换到新的信号槽样式。有关详细信息,请参阅PyQt documentation
    • 同意@three_pineapples 所说的。但是说老式的信号定义必须是函数的形式是错误的。事实上,any 字符串可用于自定义信号——甚至是空字符串!唯一重要的是字符串匹配(尽管不是完全 - 空格被忽略)。 OPs 示例中的真正错误是它没有运行事件循环——这是处理异步、跨线程信号所必需的,但不是处理同步、直接信号所必需的。
    • 在我的带有 PySide 的计算机上,省略括号会导致分段错误。
    • 请阅读 PySide 不支持非 C 形式的旧式信号定义,因此即使在 PyQt 上也最好不要使用它们。见这里:wiki.qt.io/…
    • @ekhumoro。我同意,我更新了答案,提到它只是 PySide 需要的,并且更加强调新型信号/插槽。
    【解决方案2】:

    我自己搞砸了,我认为这对你有用。

    from PyQt4.QtCore import * 
    from PyQt4.QtGui import *
    from PyQt4 import QtCore
    
    class WorkThread(QtCore.QThread):
     def __init__(self):
      QtCore.QThread.__init__(self)
    
     tryThis =    QtCore.Signal(str)   #added this variable
    
     def run(self):
      print("From thread")
      x = "trying"
      self.tryThis.emit(QtCore.SIGNAL(x))  #pass your new variable like this
      return
    
    class Foo(QObject):
    
        def handle_trigger(self):
            print ("trigger signal received")
    
        def new_thread(self):
            self.get_thread = WorkThread()        
            self.get_thread.start()
            self.get_thread.tryThis.connect(self.handle_trigger,QtCore.Qt.QueuedConnection)  #passed it here
    
    a = Foo()
    a.new_thread()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-04
      • 2010-10-15
      • 1970-01-01
      • 2011-02-04
      • 2017-03-25
      相关资源
      最近更新 更多