Auf dieser Seite

TaskTree-Ampel

Veranschaulicht anhand einer Ampel-Simulation, wie sich das Verhalten einer Zustandsmaschine mithilfe von TaskTree umsetzen lässt.

Die TaskTree-Ampel ist eine alternative Implementierung der Ampel-Beispiele in Qt SCXML und Qt State Machine.

Ampel mit leuchtendem grünen Licht und Pause-Taste

Die Anwendung besteht aus drei Hauptkomponenten:

  • Ein „ TrafficLight “-Widget, das den aktuellen Zustand anzeigt.
  • Ein „ TaskTree “-Rezept, das Zustandsübergänge steuert.
  • Ein „ GlueInterface “, das die Benutzeroberfläche mit der Zustandsmaschine synchronisiert.

In den folgenden Abschnitten werden weitere Details zum Code des Beispiels beschrieben.

Hilfsklasse

Die Klasse „ GlueInterface “ sorgt für eine klare Trennung zwischen der Benutzeroberfläche und der Geschäftslogik.

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();
};

Die Klasse „ GlueInterface “ stellt die folgenden Schnittstellenmethoden bereit:

MethodeZweck
setLights()Aktualisiert den Status der Ampel anhand eines Rezepts aus dem TaskTree
lightsChanged()Benachrichtigt die Benutzeroberfläche bei Änderungen des Ampelzustands
smash()/ repair()Verarbeitet Fehlersimulationen und Wiederherstellungsmaßnahmen

Wenn Benutzer mit der Benutzeroberfläche interagieren:

  • Löst durch Klicken auf „Pause“ die Aktion „ smash() “ aus und simuliert so eine Störung.
  • Ein Klick auf „Weiter“ löst ` repair()` aus und stellt den Normalbetrieb wieder her.

Implementierung der Zustandsmaschine

Die Logik der Zustandsmaschine wird über ein „TaskTree“-Rezept implementiert. Die Methode ` recipe() ` erstellt diese Logik mithilfe eines Verweises auf ` 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
            }
        }
    };
}
Verwaltung des Wurzelzustands

Das Element „ Forever “ auf oberster Ebene führt seine untergeordneten Elemente in einer Endlosschleife aus. Es enthält zwei Untergruppen, die den funktionierenden und den fehlerhaften Zustand darstellen.

Regeln für den Zustandsübergang:

  • Zustände werden nacheinander ausgeführt, da das Standard-„ execution mode “ sequential ist.
  • Wenn ein Zustand abgeschlossen ist, beginnt der nächste.
  • Übergänge werden ausgelöst, wenn ein Benutzer in der Benutzeroberfläche auf die Pause- oder Wiedergabetaste klickt und dabei das entsprechende Signal ausgibt.
Der Betriebszustand „working“

Der Arbeits Group besteht aus zwei Aufgaben, die in „ parallel “ ausgeführt werden:

  • Der „ signalAwaiterTask “ ist mit dem Signal „ GlueInterface::smashed “ verbunden. Wird das Signal ausgelöst, beendet die Aufgabe sofort die Ausführung mit „ DoneResult::Success “. Dies führt dazu, dass der „working“ Group die Ausführung stoppt und das Rezept in den „broken“- Zustand wechselt.
  • Die verschachtelte „ Forever “-Aufgabe besteht aus vier „ switchLightsTask “-Aufgaben („red“, „redGoingGreen“, „green“ und „greenGoingRed“), die in einer Endlosschleife mit „ sequentially “ ausgeführt werden.

Das „ stopOnSuccess “-Element jeder Gruppe weist diese an, die Ausführung zu beenden, sobald eine ihrer untergeordneten Aufgaben mit „ DoneResult::Success “ abgeschlossen ist.

Die Implementierung von „ switchLightsTask “:

  • Aktualisiert die Lichtzustände über „ GlueInterface::setLights() “.
  • Erzeugt eine zeitgesteuerte Verzögerung mithilfe von „ timeoutTask “.
  • Behält den Zustand für die angegebene Dauer bei („ timeout “).
static Group switchLightsTask(GlueInterface *iface, Lights lights, const milliseconds &timeout)
{
    return {
        onGroupSetup([iface, lights] { iface->setLights(lights); }),
        timeoutTask(timeout, DoneResult::Success)
    };
}
Der „fehlerhafte“ Betriebszustand

Der defekte „ Group “ ähnelt dem funktionierenden „ Group “. Der einzige Unterschied besteht darin, dass er mit dem Signal „ GlueInterface::repaired “ verbunden ist und die Leuchten nur zwischen zwei Zuständen wechseln, wobei das gelbe Licht ein- und ausgeschaltet wird.

Einrichtung der Anwendung

Die Haupteinrichtung der Anwendung erstellt alle Komponenten und verbindet sie miteinander:

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();
}

Die Funktion „ main() “ instanziiert die Objekte „QApplication“, „ GlueInterface “, „QTaskTree“ und „ TrafficLight “.

Um das ` taskTree `-Objekt zu erstellen, übergeben wir ein ` recipe() `, das mit dem ` iface `-Objekt erstellt wurde. Die ` widget ` verwendet ebenfalls das übergebene ` iface `-Objekt.

Vor der Ausführung der Anwendung zeigt die Funktion „ main() “ das Widget „ TrafficLight “ an und startet den Aufgabenbaum.

Ausführen des Beispiels

Sie können das Beispiel wie folgt ausführen:

Beispielprojekt @ 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.