未发出线程之间的 PyQt 信号

PyQt signals between threads not emitted

我卡住了。它应该很容易,我已经使用 Qt 的 C++ API 完成了很多次,但是由于某种原因,当我在 PyQt 中执行此操作时,我的几个 signals/slots 不工作(我最近开始与 PyQt 中工人 QObject 的概念)。我相信它必须对我发出信号的单独线程做一些事情 to/from.

from PyQt4.QtCore import QThread, QObject, pyqtSignal, pyqtSlot, QTimer
from PyQt4.QtGui import QApplication, QWidget, QVBoxLayout, QPushButton, QLabel

class Slave(QObject):

  countSignal = pyqtSignal(int)

  def __init__(self, parent = None):
    super(Slave, self).__init__()

    self.toggleFlag = False
    self.counter = 0

  @pyqtSlot()
  def work(self):
    if not self.toggleFlag: return

    if self.counter > 10: self.counter = 0
    self.counter += self.counter
    self.countSignal.emit(self.counter)

  @pyqtSlot()
  def toggle(self):
    self.toggleFlag = not self.toggleFlag


class Master(QWidget):

  toggleSignal = pyqtSignal()

  def __init__(self, parent = None):
    super(Master, self).__init__()

    self.initUi()
    self.setupConn()

  def __del__(self):
    self.thread.quit()
    while not self.thread.isFinished(): pass

  def initUi(self):
    layout = QVBoxLayout()
    self.buttonToggleSlave = QPushButton('Start')
    self.labelCounterSlave = QLabel('0')
    layout.addWidget(self.buttonToggleSlave)
    layout.addWidget(self.labelCounterSlave)
    self.setLayout(layout)
    self.show()

  def setupConn(self):
    self.thread = QThread()
    slave = Slave()
    timer = QTimer()
    timer.setInterval(100)

    # Make sure that both objects are removed properly once the thread is terminated
    self.thread.finished.connect(timer.deleteLater)
    self.thread.finished.connect(slave.deleteLater)

    # Connect the button to the toggle slot of this widget
    self.buttonToggleSlave.clicked.connect(self.toggle)
    # Connect widget's toggle signal (emitted from inside widget's toggle slot) to slave's toggle slot
    self.toggleSignal.connect(slave.toggle)

    # Connect timer's timeout signal to slave's work slot
    timer.timeout.connect(slave.work)
    timer.timeout.connect(self.timeout)
    # Connect slave's countSignal signal to widget's viewCounter slot
    slave.countSignal.connect(self.viewCounter)

    # Start timer
    timer.start()
    # Move timer and slave to thread
    timer.moveToThread(self.thread)
    slave.moveToThread(self.thread)

    # Start thread
    self.thread.start()    

  @pyqtSlot(int)
  def viewCounter(self, value):
    print(value)
    self.labelCounterSlave.setText(str(value))

  @pyqtSlot()
  def toggle(self):
    print("Toggle called")
    self.buttonToggleSlave.setText("Halt" if (self.buttonToggleSlave.text() == "Start") else "Start")
    self.toggleSignal.emit()

  @pyqtSlot()
  def timeout(self):
    print("Tick")


if __name__ == "__main__":
    app = QApplication([])
    w = Master()
    w.setStyleSheet('cleanlooks')
    app.exec_()

以下内容不是triggered/emitted:

我不知道我做错了什么。我已经连接了信号和槽,启动了我的计时器,将它与 worker 一起移动到我单独的线程并启动了线程。

我是不是漏掉了什么?

代码有几个问题导致无法正常工作。

  1. 根据 documentation,您必须从计时器所在的线程启动(和停止)它。您不能从另一个线程启动它。如果你想让计时器驻留在线程中,你应该将实例化代码重新定位到 Slave 对象并在连接到线程 started 信号的槽中调用 timer.start() 。你在这里确实需要小心,因为 Slave.__init__ 方法仍然会在主线程中 运行 。或者,您可以将计时器留在主线程中。

  2. setupConn() 完成时,
  3. slavetimer 正在被垃圾回收。将它们存储为 self.slaveself.timer。 (或者,您应该能够为它们指定父级,但这似乎会导致应用程序在退出时崩溃,因此最好坚持将它们存储为实例属性)。

  4. 我假设行 self.counter += self.counter 真的应该是 self.counter += 1?否则计数器永远不会递增:)