Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. How to properly restart QStateMachine
Forum Updated to NodeBB v4.3 + New Features

How to properly restart QStateMachine

Scheduled Pinned Locked Moved Solved Qt for Python
3 Posts 2 Posters 282 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    Anonimista
    wrote on last edited by Anonimista
    #1

    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 each QPushButton 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 using QStateMachine.start() and QStateMachine.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 its stopped and start 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())
    
    
    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      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.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      A 1 Reply Last reply
      2
      • SGaistS SGaist

        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.

        A Offline
        A Offline
        Anonimista
        wrote on last edited by
        #3

        @SGaist

        Thanks

        1 Reply Last reply
        0
        • A Anonimista has marked this topic as solved on

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved