我卡住了。使用Qt的C++ API,这应该很容易,而且我已经做过很多次,但是出现了问题,当我在PyQt中尝试时,我的几个信号/槽没有起作用(最近我开始使用PyQt中的Worker QObject的概念)。我相信这与我正在发射信号到/从分离线程有关。
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_()
以下内容未被触发/发出:
- 我的小部件的
timeout()
插槽 - 我添加了这个插槽以查看为什么定时器不能触发我的worker插槽,但我发现它在这里也不起作用......
- Slave
worker类内部的work()
和toggle()
插槽。
- countSignal
- 它从未被发出,因为我的小部件的viewCounter()
插槽从未被触发。我不知道我做错了什么。我已经连接了信号和插槽,启动了我的定时器,将其与worker一起移动到我的单独线程并启动了线程。
这里我是否漏掉了什么?
self.slave
和self:timer
,我也认为它们超出了范围,但是我太习惯C++版本了,在那里,你要将指针传递给这两个线程,所以我没有想到在此更改。不过,我有一个问题——在C++中,如果您打算将这些东西移动到另一个线程中,则将其创建为类成员是不正确的。我猜Python不是这种情况吗?这不会使QObject.deleteLater()
变得毫无意义吗? - rbaleksandardeleteLater()
应该仍然有效,如果您尝试在剩余引用之后访问已删除的Qt对象,则会在终端上打印有关底层C++对象已被删除的警告。 - three_pineapplesself
,但在Python中传递参数的方式与我们在C++中控制它是通过引用还是值有些不同。如果从属和计时器是部件类的一部分(在我的情况下),那么一旦小部件被销毁,它也应该销毁包括这两个在内的所有成员。嗯... - rbaleksandar