Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Dynamic number of parallel states in a state machine
QtWS25 Last Chance

Dynamic number of parallel states in a state machine

Scheduled Pinned Locked Moved Solved General and Desktop
statemachineqstatemachinescxmlpyside2python
2 Posts 1 Posters 773 Views
  • 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.
  • R Offline
    R Offline
    rledisez
    wrote on 6 Nov 2018, 07:43 last edited by
    #1

    Hi all,

    I'm trying to dev my first desktop application using Qt. I used to work with statecharts on previous projects, so I'm trying to do the same with Qt. But I'm facing a design issue I don't know how to work around.

    The application is developped with PySide2 (Python). It will be managed by a state machine, created with QScxmlStateMachine.fromFile(). To simplify, there is 2 states [Login, Operate(Parallel)]. In the Operate state, the user can create multiple tabs. Each tab must be managed by a/the statemachine. This is were I'm stuck. The Operate state mode must be "parallel", so that each tab has its own state and run in parallel. But, as the number of tabs are dynamic, I cannot create them in advance. And from my understanding, all states of a statemachine must be created before the statemachine is started. So, I tried to workaround by creating one statemachine with QScxmlStateMachine.fromFile() per tab. But I end up in weird situation: the "child" statemachine does not start, except if I raise an Exception (I feel it could be somehow related to the event loop, but I'm don't know Qt enough yet).

    I think I miss a design pattern here. Any help/tips/lessons are welcomed :)

    Thx for your help.

    1 Reply Last reply
    0
    • R Offline
      R Offline
      rledisez
      wrote on 6 Nov 2018, 17:32 last edited by
      #2

      By writing a small demo to complete my post, I found the issue. As it might be helpful to somebody else, here it is:

      demo.scxml:

      <?xml version="1.0" encoding="UTF-8"?>
      <scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" binding="early" xmlns:qt="http://www.qt.io/2015/02/scxml-ext" name="plop.scxml" qt:editorversion="4.7.1">
          <state id="State_1">
              <qt:editorinfo scenegeometry="144.50;162.05;84.50;112.05;120;100" geometry="144.50;162.05;-60;-50;120;100"/>
          </state>
      </scxml>
      

      demo.py:

      #!/usr/bin/env python
      
      import sys
      
      from PySide2.QtCore import QObject, QCoreApplication, SLOT, Slot
      from PySide2.QtScxml import QScxmlStateMachine
      
      
      class Backend_1(QObject):
          def __init__(self, machine):
              super(Backend_1, self).__init__()
              self.machine = machine
              self.machine.connectToState("State_1", self, SLOT("s1_active(bool)"))
      
          @Slot(bool)
          def s1_active(self, active):
              if active:
                  print('Backend_1::State_1: enter')
                  self.submachine = QScxmlStateMachine.fromFile('demo.scxml')
                  b = Backend_2(self.submachine)
                  self.submachine.start()
              else:
                  print('Backend_1::State_1: exit')
      
      
      class Backend_2(QObject):
          def __init__(self, machine):
              super(Backend_2, self).__init__()
              self.machine = machine
              self.machine.connectToState("State_1", self, SLOT("s1_active(bool)"))
      
          @Slot(bool)
          def s1_active(self, active):
              if active:
                  print('Backend_2::State_1: enter')
              else:
                  print('Backend_2::State_1: exit')
      
      
      if __name__ == '__main__':
          app = QCoreApplication(sys.argv)
      
          machine = QScxmlStateMachine.fromFile('demo.scxml')
          b = Backend_1(machine)
          machine.start()
      
          sys.exit(app.exec_())
      

      If you run this, you expect to see:
      Backend_1::State_1: enter
      Backend_2::State_1: enter

      But, the second statemachine does not seem to start. To fix it, you need to store the instance of Backend_2 (eg: self.b = Backend_2(self.submachine)). I guess it was garbage collected, so all the states/events connections were broken.

      Meanwhile, if you think my design patter is bad, I'm willing to learn :)

      1 Reply Last reply
      0

      1/2

      6 Nov 2018, 07:43

      • Login

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