Cours:TPqtFNS : Différence entre versions

De troyesGEII
Aller à : navigation, rechercher
(diy transition)
(diy transition)
Ligne 129 : Ligne 129 :
  
 
=diy transition=
 
=diy transition=
 +
 +
<source lang=cpp>
 +
    ConditionnalTransition * t3=new ConditionnalTransition(ui->bpChange,&QPushButton::clicked, s1);
 +
    t3->setTargetState(s3);
 +
    connect(ui->choix,&QCheckBox::toggled,t3,&ConditionnalTransition::setEnable);
 +
    t3->setInitState(ui->choix->isChecked());
 +
</source>
  
 
{|style="vertical-align:middle; width:100%; text-align:left; "
 
{|style="vertical-align:middle; width:100%; text-align:left; "

Version du 26 septembre 2024 à 10:58

Machine à état fini

Les automates à états finis sont en moyen de décrire un système avec des comportements différents.

A chaque état est associé un comportement.

Des transitions permettent de passer d'un état à un autre

A chaque transition est associé une condition pour valider ce changement d'état.


Vous pouvez consulter la page wikipedia pour plus de détails.


La librairie QT permet de décrire facilement des Finite State Machine à l'aide d'un ensemble de classes listées sur la page statemachine-api.html


Prise en main de l'api FSM

En vous servant de la page statemachine-api.html, écrire un programme répondant au cahier des charges suivant :

  • sur l'interface graphique, disposez 2 objets :
    • led : de type WidgetLampe (classe donnée ci dessous, cf séance sur la spécialisation de widget pour l'ajouter)
    • bp  : de type QPushButton
  • le comportement est le suivant :
    • il y a 3 états différents (stateRouge,stateVert,stateNoir)
    • on change d'état à l'appui sur bp
    • la led sera :
      • rouge dans l'état stateRouge
      • verte dans l'état stateVert
      • noire dans l'état stateNoir


Diagetat1.png

widgetlampe.h

#ifndef WIDGETLAMPE_H
#define WIDGETLAMPE_H

#include <QPushButton>

class WidgetLampe : public QPushButton
{
    Q_OBJECT
public:
    explicit WidgetLampe(QWidget *parent = 0);

signals:

public slots:
    void changeCouleur(int etat);
    void setRouge();
    void setVert();
    void setNoir();

};

#endif // WIDGETLAMPE_H

lampe.cpp

#include "widgetlampe.h"
#include <QDebug>

WidgetLampe::WidgetLampe(QWidget *parent) : QPushButton(parent)
{
    this->setDisabled(true);
}

void WidgetLampe::changeCouleur(int etat)
{
    qDebug()<<"change";
    QString style = "background-color: rgb(%1, %2, %3);";
    this->setStyleSheet(style.arg(etat*25).arg(0).arg(0));
}

void WidgetLampe::setRouge()
{
    qDebug()<<"rouge";
    QString style = "background-color: rgb(%1, %2, %3);";
    this->setStyleSheet(style.arg(255).arg(0).arg(0));
}

void WidgetLampe::setVert()
{
    qDebug()<<"vert";
    QString style = "background-color: rgb(%1, %2, %3);";
    this->setStyleSheet(style.arg(0).arg(255).arg(0));
}

void WidgetLampe::setNoir()
{
    qDebug()<<"noir";
    QString style = "background-color: rgb(%1, %2, %3);";
    this->setStyleSheet(style.arg(0).arg(0).arg(0));
}


Ajout de sous-états

Dans certains cas, il peut être intéressant d'avoir une machine d'état qui décrit le comportement d'un état, une machine d'état dans la machine d'état.

Ceci est décrit sur la page qt à cet endroit.


On souhaite ajouter au diagramme précédent une étape de clignotement :

  • on ajoute 1 état stateClignote
  • on ajoute 2 sous-états stateClignoteOn et clignoteOff
  • il nous faut un objet tictoc de type QTimer
    • le signal timeout permettra la transition entre les sous-états
    • on veillera à mettre en route/arrêter le timer au bon moment

Remarque : il existe 2 slots start dans la classe QTimer, il faut sélectionner le bon :

    connect(s3, &QState::entered,
            &ticToc, QOverload<>::of(&QTimer::start));

Diagetat2.png

diy transition

    ConditionnalTransition * t3=new ConditionnalTransition(ui->bpChange,&QPushButton::clicked, s1);
    t3->setTargetState(s3);
    connect(ui->choix,&QCheckBox::toggled,t3,&ConditionnalTransition::setEnable);
    t3->setInitState(ui->choix->isChecked());

conditionnaltransition.h

#ifndef CONDITIONNALTRANSITION_H
#define CONDITIONNALTRANSITION_H

#include <QSignalTransition>
#include <QCheckBox>

class ConditionnalTransition : public QSignalTransition
{
    Q_OBJECT

public:
    ConditionnalTransition(const QObject *sender, const char * signal, QState *sourceState = nullptr);

    template <typename Func>
    ConditionnalTransition(const typename QtPrivate::FunctionPointer<Func>::Object *obj,
                      Func sig, QState *srcState = nullptr)
        : ConditionnalTransition(obj, QMetaMethod::fromSignal(sig).methodSignature().constData(), srcState)
    {
    }

    bool eventTest(QEvent *event) override;
    void setInitState(bool newEtat);

private:
    bool etat;

public slots:
    void setEnable(bool newEtat);
    void setDisable(bool newEtat);

signals:

};

#endif // CONDITIONNALTRANSITION_H

conditionnaltransition.cpp

#include "conditionnaltransition.h"

ConditionnalTransition::ConditionnalTransition(const QObject *sender, const char * signal, QState *sourceState)
    : QSignalTransition{sender, signal, sourceState}
{
    etat=false;
}

void ConditionnalTransition::setEnable(bool newEtat)
{
    etat = newEtat;
}

void ConditionnalTransition::setDisable(bool newEtat)
{
    etat = ! newEtat;
}

bool ConditionnalTransition::eventTest(QEvent *event)
{
    if (etat==true)return QSignalTransition::eventTest(event);
    else return false;
}

void ConditionnalTransition::setInitState(bool newEtat)
{
    etat=newEtat;
}

Ressources