How to properly restart QStateMachine
-
I am experimenting with the state machine framework and I ran into an issue. I have a class named
BinaryInputStateMachinethat should process a list of binary digits on eachQPushButtonclick 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 startedOn 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 itsstoppedandstartto 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
-
A Anonimista has marked this topic as solved on