태스크트리 신호등
신호등 시뮬레이션을 통해 태스크트리를 사용하여 상태 머신 동작을 구현하는 방법을 보여줍니다.
태스크트리 신호등은 신호등 예제에 대한 대체 구현으로 Qt SCXML 와 Qt State Machine.

이 애플리케이션은 세 가지 주요 구성 요소로 이루어져 있습니다:
- 현재 상태를 표시하는
TrafficLight위젯. - 상태 전환을 제어하는
TaskTree레시피. - UI를 상태 머신과 동기화하는
GlueInterface.
다음 섹션에서는 예제 코드에 대한 자세한 내용을 설명합니다.
헬퍼 글루 클래스
GlueInterface 클래스는 UI와 운영 로직을 깔끔하게 분리합니다.
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(); };
GlueInterface 클래스는 다음과 같은 인터페이스 메서드를 제공합니다:
| 메서드 | 목적 |
|---|---|
setLights() | 태스크트리 레시피에서 신호등 상태를 업데이트합니다. |
lightsChanged() | 신호등 상태가 변경되면 UI에 알림 |
smash()/ repair() | 오류 시뮬레이션 및 복구 작업 처리 |
사용자가 UI와 상호작용할 때
- 일시 중지를 클릭하면
smash(), 오류 시뮬레이션이 트리거됩니다. - 재생을 클릭하면
repair(), 정상 작동을 복원합니다.
상태 머신 구현하기
상태 머신 로직은 태스크트리 레시피를 통해 구현됩니다. recipe() 메서드는 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 } } }; }
루트 상태 관리
최상위 수준 Forever 항목은 무한 루프에서 자식을 실행합니다. 여기에는 작동 상태와 중단 상태를 나타내는 두 개의 하위 그룹이 포함되어 있습니다.
상태 전환 규칙:
- 기본값 execution mode 은 sequential 이므로 상태는 순서대로 실행됩니다.
- 한 상태가 완료되면 다른 상태가 시작됩니다.
- 전환은 사용자가 UI에서 일시 중지 또는 재생 버튼을 클릭하면 트리거되어 해당 신호를 발산합니다.
"작동 중" 작업 상태
작동 중인 Group 은 parallel 에서 실행되는 두 개의 작업으로 구성됩니다:
- signalAwaiterTask 은
GlueInterface::smashed신호에 연결됩니다. 신호가 트리거되면 작업은 DoneResult::Success 으로 즉시 완료됩니다. 그러면 작업 중인 Group 이 실행을 중지하고 레시피가 중단된 상태로 전환됩니다. - 중첩된 Forever 작업은 무한 루프에서 sequentially 실행되는 네 개의
switchLightsTask작업("red", "redGoingGreen", "green" 및 "greenGoingRed")으로 구성됩니다.
각 그룹의 stopOnSuccess 항목은 하위 작업 중 하나가 DoneResult::Success 으로 완료되면 실행을 중지하도록 지시합니다.
switchLightsTask 구현:
GlueInterface::setLights()을 통해 조명 상태를 업데이트합니다.- timeoutTask 을 사용하여 시간 지연을 생성합니다.
- 지정된 기간 동안 상태를 유지합니다
timeout.
static Group switchLightsTask(GlueInterface *iface, Lights lights, const milliseconds &timeout) { return { onGroupSetup([iface, lights] { iface->setLights(lights); }), timeoutTask(timeout, DoneResult::Success) }; }
"깨진" 작업 상태
깨진 Group 은 작동 중인 Group 과 유사합니다. 유일한 차이점은 GlueInterface::repaired 신호에 연결되며 노란색 표시등을 켜고 끄는 두 가지 상태 사이에서만 표시등이 순환한다는 것입니다.
애플리케이션 설정
기본 애플리케이션 설정은 모든 구성 요소를 생성하고 연결합니다:
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(); }
main() 함수는 QApplication, GlueInterface, QTaskTree 및 TrafficLight 객체를 인스턴스화합니다.
taskTree 객체를 구성하려면 iface 객체로 구성된 recipe() 객체를 전달합니다. widget 는 전달된 iface 객체도 사용합니다.
애플리케이션을 실행하기 전에 main() 함수는 TrafficLight 위젯을 표시하고 작업 트리를 시작합니다.
예제 실행하기
에서 예제를 실행하려면 Qt Creator에서 예제를 실행하려면 Welcome 모드를 열고 Examples 에서 예제를 선택합니다. 자세한 내용은 Qt Creator: 튜토리얼을 참조하세요 : 빌드 및 실행하기를 참조하세요.
© 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.