Sur cette page

TaskTree Traffic Light

Démontre comment implémenter le comportement d'une machine d'état en utilisant TaskTree à travers une simulation de feux tricolores.

Le Traffic Light de TaskTree est une implémentation alternative pour les exemples de Traffic Light de Qt SCXML et Qt State Machine.

Feu de circulation avec lumière verte allumée et bouton de pause

L'application se compose de trois éléments principaux :

  • Un widget TrafficLight qui affiche l'état actuel.
  • Une recette TaskTree qui contrôle les transitions d'état.
  • Un GlueInterface qui synchronise l'interface utilisateur avec la machine à états.

Les sections suivantes décrivent plus en détail le code de l'exemple.

Classe d'aide Glue

La classe GlueInterface assure une séparation nette entre l'interface utilisateur et la logique opérationnelle.

enum class Light
{
    Off    = 0,
    Red    = 1 << 0,
    Yellow = 1 << 1,
    Green  = 1 << 2,
};

Q_DECLARE_FLAGS(Lights, Light)
Q_DECLARE_OPERATORS_FOR_FLAGS(Lights)

class GlueInterface final : public QObject
{
    Q_OBJECT

public:
    // operational logic -> GUI
    void setLights(Lights lights) { emit lightsChanged(lights); }

    // GUI -> operational logic
    void smash() { emit smashed(); }
    void repair() { emit repaired(); }

signals:
    void lightsChanged(Lights lights);

    void smashed();
    void repaired();
};

La classe GlueInterface fournit les méthodes d'interface suivantes :

MéthodeObjectif
setLights()Mise à jour de l'état des feux de signalisation à partir de la recette de l'arbre des tâches
lightsChanged()Notifie l'interface utilisateur lorsque l'état des feux change
smash()/ repair()Gère la simulation de panne et les actions de récupération

Lorsque les utilisateurs interagissent avec l'interface utilisateur :

  • Un clic sur pause déclenche smash(), simulant une panne.
  • Un clic sur play déclenche repair(), rétablissant le fonctionnement normal.

Mise en œuvre de la machine à états

La logique de la machine à états est mise en œuvre par le biais d'une recette TaskTree. La méthode recipe() crée cette logique en utilisant une référence à GlueInterface:

ExecutableItem recipe(GlueInterface &iface)
{
    return Forever {
        Group { // "working" state
            stopOnSuccess,
            parallel,
            signalAwaiterTask(&iface, &GlueInterface::smashed), // transitions to the "broken" state
            Forever {
                switchLightsTask(&iface, Light::Red, 3s), // "red" state
                switchLightsTask(&iface, Light::Red | Light::Yellow, 1s), // "redGoingGreen" state
                switchLightsTask(&iface, Light::Green, 3s), // "green" state
                switchLightsTask(&iface, Light::Yellow, 1s), // "greenGoingRed" state
            }
        },
        Group { // "broken" state
            stopOnSuccess,
            parallel,
            signalAwaiterTask(&iface, &GlueInterface::repaired), // transitions to the "working" state
            Forever {
                switchLightsTask(&iface, Light::Yellow, 1s), // "blinking" state
                switchLightsTask(&iface, Light::Off, 1s), // "unblinking" state
            }
        }
    };
}
Gestion de l'état racine

L'élément de niveau supérieur Forever exécute ses enfants dans une boucle infinie. Il contient deux sous-groupes représentant les états de fonctionnement et de rupture.

Règles de transition des états :

  • Les états s'exécutent en séquence, car par défaut execution mode est sequential.
  • Lorsqu'un état est terminé, l'autre commence.
  • Les transitions sont déclenchées lorsqu'un utilisateur clique sur le bouton "pause" ou "lecture" de l'interface utilisateur, émettant ainsi le signal correspondant.
L'état de fonctionnement "opérationnel

L'état de fonctionnement Group se compose de deux tâches exécutées dans parallel:

  • La tâche signalAwaiterTask se connecte au signal GlueInterface::smashed. Si le signal est déclenché, la tâche se termine immédiatement avec DoneResult::Success. Cela entraîne l'arrêt de l'exécution de la tâche Group et le passage de la recette à l'état "broken".
  • La tâche imbriquée Forever se compose de quatre tâches switchLightsTask ("red", "redGoingGreen", "green" et "greenGoingRed") exécutées sequentially dans une boucle infinie.

L'élément stopOnSuccess de chaque groupe lui indique d'arrêter son exécution lorsque l'une de ses tâches enfantines se termine par DoneResult::Success.

L'implémentation de switchLightsTask:

  • met à jour les états lumineux via GlueInterface::setLights().
  • Crée un délai temporel à l'aide de timeoutTask.
  • Maintient l'état pour la durée spécifiée timeout.
static Group switchLightsTask(GlueInterface *iface, Lights lights, const milliseconds &timeout)
{
    return {
        onGroupSetup([iface, lights] { iface->setLights(lights); }),
        timeoutTask(timeout, DoneResult::Success)
    };
}
L'état de fonctionnement "cassé

L'état "broken" Group est similaire à l'état " working" Group. La seule différence est qu'il se connecte au signal GlueInterface::repaired, et que les lumières passent seulement d'un état à l'autre pour allumer et éteindre la lumière jaune.

Configuration de l'application

La configuration de l'application principale crée et connecte tous les composants :

int main(int argc, char **argv)
{
    QApplication app(argc, argv);

    GlueInterface iface;
    QTaskTree taskTree({recipe(iface)});
    TrafficLight widget(iface);

    widget.show();
    taskTree.start();

    return app.exec();
}

La fonction main() instancie les objets QApplication, GlueInterface, QTaskTree et TrafficLight.

Pour construire l'objet taskTree, nous passons un recipe() construit avec l'objet iface. La fonction widget utilise également l'objet iface transmis.

Avant d'exécuter l'application, la fonction main() affiche le widget TrafficLight et démarre l'arbre des tâches.

Exécution de l'exemple

Pour exécuter l'exemple à partir de Qt CreatorOuvrez le mode Welcome et sélectionnez l'exemple à partir de Examples. Pour plus d'informations, voir Qt Creator: Tutoriel : Construire et exécuter.

Exemple de projet @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.