Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. International
  3. French
  4. Traitement des évènements d'une QScxmlStateMachine

Traitement des évènements d'une QScxmlStateMachine

Scheduled Pinned Locked Moved Solved French
11 Posts 3 Posters 844 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.
  • M Offline
    M Offline
    Max
    wrote on 30 Aug 2024, 16:26 last edited by
    #1

    Bonjour,

    J'utilise avec bonheur QScxmlStateMachine depuis deux ou trois semaine.
    Une première machine d'états suit l'état d'une base de données, et tout fonctionne bien.
    Une seconde machine d'états fonctionne moins bien et j'aimerais vos lumières.

    Lorsque je déclenche un changement d'états avec submitEvent, je constate que le changement effectif d'état n'a pas lieu de suite, mais juste avant que l'application redonne la main à l'utilisateur. Or entre le submitEvent et l'attente d'une action utilisateur je réalise des opérations qui dépendent de l'état actif.

    J'ai l'impression que la boucle des évènements ne traite ceux de la machine d'états qu'en dernier.
    Alors j'ai cherché en vainc dans l'API de QScxmlStateMachine comment "purger" la file des évènements juste après le submitEvent.

    Quelqu'un sait ce qu'il faut faire ?
    Sylvain

    1 Reply Last reply
    0
    • M Offline
      M Offline
      Max
      wrote on 5 Jan 2025, 10:38 last edited by
      #11

      Bonjour,

      Je m'apperçois que je n'ai pas clôturé ce fil.
      La solution est d'évaluer le bout de code à l'entrée dans l'état cible, ce qui se fait simplement avec connectToState().
      De cette façon, même si le changement d'état a lieu tardivement, le code est évalué à l'entrée dans l'état.
      Bref... encore un problème issu de ma méconnaissance de l'API des QScxmlStateMachine.

      1 Reply Last reply
      0
      • M Offline
        M Offline
        Max
        wrote on 31 Aug 2024, 10:24 last edited by
        #2

        Bonjour,

        Solution trouvée : appeler
        QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
        juste après un
        submitEvent();

        Cette solution n'est pas préconisée par la doc Qt. J'ai donc essayé de récupérer un handle vers la QEventLoop de l'application mais je ne trouve pas comment faire...

        1 Reply Last reply
        0
        • S Offline
          S Offline
          SGaist
          Lifetime Qt Champion
          wrote on 31 Aug 2024, 18:45 last edited by
          #3

          qApp->processEvents(QEventLoop::ExcludeUserInputEvents)

          C'est une macro qui return l'object Q(Core,Gui)Application.

          processEvents est de toute façon une méthode static donc c'est la bonne event loop qui est appelée. Ce qui n'est pas recommandé est l'usage de cette méthode.

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

          1 Reply Last reply
          0
          • M Offline
            M Offline
            Max
            wrote on 1 Sept 2024, 12:08 last edited by
            #4

            ... oui, c'est bien ce que j'ai écrit.

            Mais si l'usage de cette commande n'est pas recommandée, comment faire autrement ?

            1 Reply Last reply
            0
            • M Offline
              M Offline
              Matebiz Pvt. Ltd.
              wrote on 3 Sept 2024, 06:44 last edited by Matebiz Pvt. Ltd. 9 Mar 2024, 06:45
              #5
              This post is deleted!
              1 Reply Last reply
              0
              • M Offline
                M Offline
                Max
                wrote on 11 Sept 2024, 11:20 last edited by
                #6

                Depuis le temps j'ai pensé à une autre solution potentielle :

                • créer une nouvelle boucle d'évènements dans celle de l'IHM ;
                • "raccrocher" les évènements des QScxmlStateMachine à cette nouvelle boucle d'évènements.

                Si le premier point est assez simple, je ne sais pas encore comment assurer le second. Ce serait possible ?

                1 Reply Last reply
                0
                • S Offline
                  S Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on 11 Sept 2024, 18:01 last edited by
                  #7

                  Serait-il possible d'avoir un démonstrateur minimal qui permette de voir le soucis de cette state machine ?

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

                  1 Reply Last reply
                  0
                  • M Offline
                    M Offline
                    Max
                    wrote on 19 Sept 2024, 16:54 last edited by
                    #8

                    Bonjour,

                    Je m'y essaye !

                    Voici la machine d'états définie dans Qt Creator.
                    SM_EtatsFormulaire.png

                    Voici le .h et le .cpp d'un widget formulaire intégré à un MainWindow. Ce widget compte plusieurs champs et cases à cocher. J'ai réduit au maximum.

                    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                    /// form.h
                    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                    
                    #include "SM_EtatsFormulaire.h"
                    #include "donneurs.h"
                    
                    namespace Ui {
                    class Form;
                    }
                    
                    class Form : public QWidget
                    {
                        Q_OBJECT
                    
                    public:
                        explicit Form(QWidget *parent = nullptr);
                        ~Form();
                    
                        void lancer_machine_etats();
                        void renseigne_formulaire(Donneur *d);
                        
                    signals:
                        void formChanged();   
                        
                    private slots:
                        void formulaireModifie();
                        void on_pushButton_RAZ_clicked();
                        
                    private:
                        void formulaireValide(bool);
                        void makeupLabelId();
                        void sm_emit_Vider_formulaire();
                        void sm_emit_Valider_formulaire();
                        void sm_emit_Selectionner_donneur_en_base();
                        void doItNow();
                        
                        Ui::Form            *   ui;
                    
                        SM_EtatsFormulaire      sm_etat_formulaire;
                    };
                    
                    
                    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                    /// form.cpp
                    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                    
                    #include "form.h"
                    #include "ui_form.h"
                    
                    Form::Form(QWidget *parent) :
                        QWidget(parent),
                        ui(new Ui::Form)
                    {
                        ui->setupUi(this);
                        lancer_machine_etats();
                    }
                    
                    Form::~Form(){
                        delete ui;
                    }
                    
                    void Form::lancer_machine_etats(){
                        sm_etat_formulaire.connectToState("Formulaire_Non_Valide",
                                                            [this](bool active) { if (active) this->formulaireModifie(); }
                                                         );
                        sm_etat_formulaire.connectToState("Formulaire_Valide",
                                                            [this](bool active) { this->formulaireValide(active);            }
                                                         );
                        sm_etat_formulaire.start();
                    }
                    
                    void Form::formulaireModifie(){
                        emit formChanged();
                        if (donneurs->filtre.isValid()) sm_emit_Valider_formulaire();
                    }
                    
                    void Form::formulaireValide(bool b){
                        ui->pushButton_select_donneurs->setEnabled(b);
                    }
                    
                    void Form::on_pushButton_RAZ_clicked(){
                        vider_formulaire();
                        formulaireModifie();
                        sm_emit_Vider_formulaire();
                        makeupLabelId();
                    }
                    
                    /// Méthode appelée par MainWindow après sélection d'un donneur dans un QTableView.
                    void Form::renseigne_formulaire(element *d){
                    [...]
                        sm_emit_Selectionner_donneur_en_base();
                        formulaireModifie();
                        makeupLabelId();
                    }
                    
                    /////// Le soucis est là.
                    // Si on ne prend pas la peine de vider la boucle des événements juste après le changement d'état, ...
                    // ... le nouvel état ne sera pas détecté ici.
                    // La transition vers le nouvel état aura lieu juste avant que MainWindow redonne la main à l'utilisateur.
                    void Form::makeupLabelId(){
                    [...]
                        if (sm_etat_formulaire.isActive("Formulaire_Vide")) badIdx = false;
                    [...]
                    }
                    
                    void Form::sm_emit_Vider_formulaire(){
                        sm_etat_formulaire.submitEvent("Vider_formulaire");
                        doItNow();
                    }
                    void Form::sm_emit_Valider_formulaire(){
                        sm_etat_formulaire.submitEvent("Valider_formulaire");
                        doItNow();
                    }
                    void Form::sm_emit_Selectionner_donneur_en_base(){
                        sm_etat_formulaire.submitEvent("Selectionner_donneur_en_base");
                        doItNow();
                    }
                    void Form::doItNow(){
                        QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
                    }
                    
                    1 Reply Last reply
                    0
                    • S Offline
                      S Offline
                      SGaist
                      Lifetime Qt Champion
                      wrote on 19 Sept 2024, 17:59 last edited by
                      #9

                      Est-ce qu'à un quelconque moment, la machine d'état arrive dans un état final ?
                      Avant d'appeler processEvent, est-ce que la machine est arrêtée ?

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

                      1 Reply Last reply
                      0
                      • M Offline
                        M Offline
                        Max
                        wrote on 20 Sept 2024, 15:47 last edited by
                        #10

                        Non. La machine d'états (ME par la suite) passe d'un état à l'autre, c'est tout. Pour autant j'utilise dans ce même programme deux autres ME qui ne posent pas de soucis, tout fonctionne comme prévu (et d'ailleurs cela m'économise du temps, du code et me permet de formaliser graphiquement la dynamique système).

                        Après quelques tests je suis arrivé à la conclusion que les évènements de la ME sont traités en dernier juste avant de rendre la main à l'utilisateur de l'IHM, ou alors c'est la boucle d'évènements qui est traitée après le code.
                        Ainsi les changements d'états ne sont pas réalisés de suite après un submitEvent(), ce qui pose problème quand on interroge l'état actif de la ME juste après le submitEvent() et avant que l'appli ne redonne la main à l'utilisateur. D'où la solution envisagée, déconseillée par la doc Qt, mais qui fonctionne.

                        Tu proposes d'arrêter la ME après chaque submitEvent() ? Auquel cas il faudrait la redémarrer avant de faire un nouveau changement d'états ?

                        J'ai imaginé une autre solution sans savoir si ça pourrait marcher :

                        • au sein de l'application lancer une autre boucle d'évènements ;
                        • raccrocher les machines d'états à cette nouvelle boucle d'évènements qui ne serait pas "poluée" par les évènements IHM.

                        Dans l'hypothèse ou le code de la boucle d'évènements n'est exécuté qu'après le code de l'application, cela ne résoudrait rien, sauf si cette nouvelle boucle d'évènement pour la ME est lancée dans un autre thread. Mais là pour moi, c'est encore un territoire inconnu...

                        1 Reply Last reply
                        0
                        • M Offline
                          M Offline
                          Max
                          wrote on 5 Jan 2025, 10:38 last edited by
                          #11

                          Bonjour,

                          Je m'apperçois que je n'ai pas clôturé ce fil.
                          La solution est d'évaluer le bout de code à l'entrée dans l'état cible, ce qui se fait simplement avec connectToState().
                          De cette façon, même si le changement d'état a lieu tardivement, le code est évalué à l'entrée dans l'état.
                          Bref... encore un problème issu de ma méconnaissance de l'API des QScxmlStateMachine.

                          1 Reply Last reply
                          0
                          • M Max has marked this topic as solved on 5 Jan 2025, 14:35

                          • Login

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