Я застрял. Это должно быть легко, и я делал это много раз, используя C++ API Qt, но по какой-то причине некоторые из моих сигналов/слотов не работают, когда я делаю это в PyQt (я недавно начал с концепции рабочего QObject
в PyQt). Я считаю, что он должен что-то делать с отдельным потоком, который я излучаю в/из своих сигналов.Сигналы PyQt между потоками, не излучаемыми
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()
слот моего виджета - я добавил это понять, почему таймер не вызывает слот моего работника, но все, что я узнал, что это Безразлично «т работать здесь либо ...work()
иtoggle()
слотов внутри моегоSlave
рабочего классаcountSignal
- это никогда не испускаются, так как мой виджетviewCounter()
никогда не срабатывает.
Я понятия не имею, что я делаю неправильно. Я подключил сигналы и слоты, запустил свой таймер, переместил его вместе с рабочим в отдельный поток и начал поток.
Я что-то упустил?
Спасибо! Я забыл о таймере. Это была главная проблема. Что касается приращения ... (facepalm) ... Yeap, он никогда не увеличивается: D Btw для 'self.slave' и' self: timer' Я также думал, что это выходит за рамки, но я так привык к версию C++, где вы передаете указатель на поток этих двух, который я не думал об этом изменить здесь. У меня есть один вопрос, хотя - на C++ неверно создавать вещи как члены класса, если вы собираетесь переместить их в другой поток. Наверное, это не так в Python? Разве это не делает 'QObject.deleteLater()' бессмысленным? – rbaleksandar
@rbaleksandar Это может быть не очень хорошая практика (хотя я не уверен, что это была бы альтернатива), но в Python нет ничего принципиально неправильного. Это просто ссылка на объект C++.'deleteLater()' должен по-прежнему работать, и если вы попытаетесь получить доступ к Qt-объекту после его удаления через оставшуюся ссылку, вы получите предупреждение, выведенное на терминал о удаленном объекте C++. –
В C++, если вы используете член класса, он будет (я не могу правильно запомнить сейчас, какое из следующего произойдет) либо сбой, либо сигналы не будут правильно выполнены, и вы в конечном итоге исправите/зафиксируете в неправильном потоке. Вот почему я пошел без «себя», но затем снова передавая аргументы в Python, немного отличается от того, что мы имеем на C++ (с точки зрения контроля, передано ли оно по ссылке или значению). Если подчиненный и таймер являются частью класса виджетов (в моем случае), то после уничтожения виджета он также должен уничтожать все его члены, включая эти два. Hmmm ... – rbaleksandar