En esta página

Semáforo TaskTree

Demuestra cómo implementar el comportamiento de una máquina de estados utilizando TaskTree a través de la simulación de un semáforo.

El Semáforo de TaskTree es una implementación alternativa para los ejemplos de Semáforo en Qt SCXML y Qt State Machine.

Semáforo con luz verde encendida y botón de pausa

La aplicación consta de tres componentes principales:

  • Un widget TrafficLight que muestra el estado actual.
  • Una receta TaskTree que controla las transiciones de estado.
  • Un GlueInterface que sincroniza la interfaz de usuario con la máquina de estados.

Las siguientes secciones describen más detalles del código del ejemplo.

Clase Helper Glue

La clase GlueInterface proporciona una separación limpia entre la interfaz de usuario y la lógica operativa.

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 clase GlueInterface proporciona los siguientes métodos de interfaz:

MétodoPropósito
setLights()Actualiza el estado del semáforo desde la receta TaskTree
lightsChanged()Notifica a la interfaz de usuario los cambios de estado de los semáforos
smash()/ repair()Gestiona la simulación de fallos y las acciones de recuperación

Cuando los usuarios interactúan con la interfaz de usuario:

  • Al hacer clic en pausa, se activa smash(), simulando un fallo.
  • Al hacer clic en reproducir se activa repair(), restableciendo el funcionamiento normal.

Implementación de la máquina de estados

La lógica de la máquina de estados se implementa a través de una receta TaskTree. El método recipe() crea esta lógica utilizando una referencia a 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
            }
        }
    };
}
Gestión del estado raíz

El elemento de nivel superior Forever ejecuta a sus hijos en un bucle infinito. Contiene dos subgrupos que representan estados de trabajo y estados rotos.

Reglas de transición de los estados:

  • Los estados se ejecutan en secuencia, ya que por defecto execution mode es sequential.
  • Cuando un estado finaliza, comienza el otro.
  • Las transiciones se activan cuando un usuario pulsa el botón de pausa o reproducción en la interfaz de usuario, emitiendo la señal correspondiente.
El estado de funcionamiento "de trabajo

El estado de funcionamiento Group consta de dos tareas que se ejecutan en parallel:

  • La signalAwaiterTask se conecta a la señal GlueInterface::smashed. Si la señal se activa, la tarea termina inmediatamente con DoneResult::Success. Esto provoca que la tarea Group deje de ejecutarse, y la receta pasa al estado roto.
  • La tarea anidada Forever consiste en cuatro tareas switchLightsTask ("red", "redGoingGreen", "green", y "greenGoingRed") ejecutadas sequentially en un bucle infinito.

El elemento stopOnSuccess de cada grupo le indica que deje de ejecutarse cuando cualquiera de sus tareas hijas termine con DoneResult::Success.

La implementación de switchLightsTask:

  • Actualiza los estados de las luces mediante GlueInterface::setLights().
  • Crea un retardo temporizado mediante timeoutTask.
  • Mantiene el estado durante la duración especificada timeout.
static Group switchLightsTask(GlueInterface *iface, Lights lights, const milliseconds &timeout)
{
    return {
        onGroupSetup([iface, lights] { iface->setLights(lights); }),
        timeoutTask(timeout, DoneResult::Success)
    };
}
El estado de operación "roto

El estado roto Group es similar al estado de funcionamiento Group. La única diferencia es que se conecta a la señal GlueInterface::repaired, y las luces ciclan sólo entre 2 estados encendiendo y apagando la luz amarilla.

Configuración de la aplicación

La configuración principal de la aplicación crea y conecta todos los componentes:

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 función main() instanciará los objetos QApplication, GlueInterface, QTaskTree y TrafficLight.

Para construir el objeto taskTree, pasamos un recipe() construido con el objeto iface. El widget también utiliza el objeto iface pasado.

Antes de ejecutar la aplicación, la función main() muestra el widget TrafficLight e inicia el árbol de tareas.

Ejecutar el ejemplo

Para ejecutar el ejemplo desde Qt Creatorabra el modo Welcome y seleccione el ejemplo de Examples. Para más información, consulte Qt Creator: Tutorial: Construir y ejecutar.

Proyecto de ejemplo @ 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.