how to use a custom signal with QStateMachine addtransition

2.3k views Asked by At

'm trying to figure out how to use my own custom signals in combination with QStateMachine. I started with a simple example from here. Now I'm trying to create a new signal mysignal and trigger a transition off of it. But I can't figure out how to structure the call to addtransition, or how to use the SIGNAL("clicked()") syntax to refer to mysignal.

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

if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    button = QPushButton()
    machine = QStateMachine()

    off = QState()
    off.assignProperty(button, 'text', 'Off')
    off.setObjectName('off')

    on = QState()
    on.setObjectName('on')
    on.assignProperty(button, 'text', 'On')

    mysignal = pyqtSignal()

    off.addTransition(mysignal, on)
    # Let's use the new style signals just for the kicks.
    on.addTransition(button.clicked, off)

    machine.addState(off)
    machine.addState(on)
    machine.setInitialState(off)
    machine.start()
    mysignal.emit()
    button.resize(100, 50)
    button.show()
    sys.exit(app.exec_())
1

There are 1 answers

2
ekhumoro On BEST ANSWER

A custom signal must be defined as a class attribute (see New-style Signal and Slot Support in the PyQt docs). So the code in your example needs to be refactored so that all the setup happens in the __init__ of a widget subclass.

Below is a demo that does that (in order to trigger the custom signal and its state transition, you must type "foo" in the line-edit whenever the button text shows "Foo"):

from PyQt4 import QtCore, QtGui

class Window(QtGui.QWidget):
    customSignal = QtCore.pyqtSignal()

    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.edit = QtGui.QLineEdit(self)
        self.edit.textChanged.connect(self.handleTextChanged)
        self.button = QtGui.QPushButton(self)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.edit)
        layout.addWidget(self.button)
        self.machine = QtCore.QStateMachine()
        self.off = QtCore.QState()
        self.off.assignProperty(self.button, 'text', 'Off')
        self.on = QtCore.QState()
        self.on.assignProperty(self.button, 'text', 'On')
        self.foo = QtCore.QState()
        self.foo.assignProperty(self.button, 'text', 'Foo')
        self.off.addTransition(self.button.clicked, self.on)
        self.on.addTransition(self.button.clicked, self.foo)
        self.foo.addTransition(self.customSignal, self.off)
        self.machine.addState(self.off)
        self.machine.addState(self.on)
        self.machine.addState(self.foo)
        self.machine.setInitialState(self.off)
        self.machine.start()

    def handleTextChanged(self, text):
        if text == 'foo':
            self.edit.clear()
            self.customSignal.emit()

if __name__ == '__main__':

    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.show()
    window.setGeometry(500, 300, 100, 100)
    sys.exit(app.exec_())