How to properly restart QStateMachine
-
I am experimenting with the state machine framework and I ran into an issue. I have a class named
BinaryInputStateMachine
that should process a list of binary digits on eachQPushButton
click and return the state it ends up in when it processes all the digits. On another button click process a new list etc. To achieve this I am usingQStateMachine.start()
andQStateMachine.stop()
in the method that processes the digits. The output is this:set() set() set() set() set() set() Final state: set() False state machine started state machine started {<PySide6.QtStateMachine.QState(0x2be22cac6b0, name = "even") at 0x000002BE248024C0>} {<PySide6.QtStateMachine.QState(0x2be22cac6b0, name = "even") at 0x000002BE248024C0>} {<PySide6.QtStateMachine.QState(0x2be22cac6b0, name = "even") at 0x000002BE248024C0>} {<PySide6.QtStateMachine.QState(0x2be22cac6b0, name = "even") at 0x000002BE248024C0>} {<PySide6.QtStateMachine.QState(0x2be22cada60, name = "odd") at 0x000002BE24802540>} {<PySide6.QtStateMachine.QState(0x2be22cac6b0, name = "even") at 0x000002BE248024C0>} Final state: {<PySide6.QtStateMachine.QState(0x2be22cac6b0, name = "even") at 0x000002BE248024C0>} True state machine started
On the first button click the state machine sends the started signals only after my loop finishes. How can I correct this? I found this thread and according to the last comment started the state machine in
__init__
and connected itsstopped
andstart
to restart it. This seems to work but I am curious if there is a proper/common way to restart a state machine.Or maybe I should not use a tight loop at all? If so how should I structure my code?
Here is my code
import sys from random import randint from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QLabel from PySide6.QtCore import QObject, Signal, Qt from PySide6.QtStateMachine import QStateMachine, QState class BinaryInputStateMachine(QObject): on_zero = Signal() on_one = Signal() done = Signal(str) def __init__(self): super().__init__() self.state_machine = QStateMachine() self.even_state = QState() self.even_state.setObjectName('even') self.odd_state = QState() self.odd_state.setObjectName('odd') self.state_machine.addState(self.even_state) self.state_machine.addState(self.odd_state) self.state_machine.setInitialState(self.even_state) self.even_state.addTransition(self.on_zero, self.odd_state) self.even_state.addTransition(self.on_one, self.even_state) self.odd_state.addTransition(self.on_zero, self.even_state) self.odd_state.addTransition(self.on_one, self.odd_state) self.state_machine.stopped.connect(self.state_machine.start) self.state_machine.started.connect(lambda: print('state machine started')) self.state_machine.start() def process_digits(self, digits): #self.state_machine.start() for digit in digits: if digit == '0': self.on_zero.emit() else: self.on_one.emit() print(self.state_machine.configuration()) if self.even_state.active(): self.done.emit('accepted!') else: self.done.emit('rejected...') print('Final state: ', self.state_machine.configuration()) self.state_machine.stop() print(self.state_machine.isRunning()) class Window(QWidget): def __init__(self): super().__init__() self.setWindowTitle("Accepts even number of zeros") self.resize(200, 200) self.submit_button = QPushButton("Submit") self.label = QLabel() self.label.setStyleSheet('font-size: 20px') self.label.setAlignment(Qt.AlignmentFlag.AlignCenter) self.setLayout(QVBoxLayout()) self.layout().addWidget(self.submit_button) self.layout().addWidget(self.label) self.machine = BinaryInputStateMachine() self.submit_button.clicked.connect(self.send_digits) self.machine.done.connect(self.display_results) def send_digits(self): self.digits = '{:b}'.format(randint(32, 63)) self.label.setText(self.digits) self.digit_list = list(self.digits) self.machine.process_digits(self.digit_list) def display_results(self, state): self.label.setText(self.label.text() + '\n' + state) if __name__ == "__main__": app = QApplication(sys.argv) window = Window() window.show() sys.exit(app.exec())
-
Hi,
You're correct, the tight loop is wrong.
The idea would be to treat your list as a queue. When entering the state, trigger a slot that will pop the top item of the list and process it until it's empty in which case you can in the final state of your machine.
-
Hi,
You're correct, the tight loop is wrong.
The idea would be to treat your list as a queue. When entering the state, trigger a slot that will pop the top item of the list and process it until it's empty in which case you can in the final state of your machine.
Thanks
-