# QStateMachine 状态机 —— 教学补充示例

> 对应方案书「C++方向 Day4」："QT 动画框架（QPropertyAnimation）与状态机实战"
> 里的状态机部分（动画部分见 [`../property_animation/`](../property_animation/README.md)）。
> 仓库 `p03/` 的 wiki 抓取内容里没有状态机相关代码，本示例是手工补写的教学
> 补充，**不属于** `tools/gen_part3.py` 的生成产物。
>
> 小提示：`QStateMachine`/`QState` 属于 **QtCore** 模块，不需要额外
> `find_package`，这也是本示例能直接放进现有 Qt5::Core 依赖里的原因。

## 概念

状态机框架用"状态 + 转换条件"描述一个对象的行为，替代手写一堆 `if/else` 或
`switch` 去判断"现在是什么状态、该往哪个状态跳"：

- `QState` —— 一个状态，可以用 `assignProperty(obj, "属性名", 值)` 声明
  "进入这个状态时，某个对象的某个属性应该变成什么值"（不用手写槽函数）；
- `addTransition(信号源, 信号, 目标状态)` —— 声明"某个信号触发时，从当前状态
  转换到目标状态"；
- `QStateMachine` —— 持有所有状态，`setInitialState()` 指定初始状态，
  `start()` 启动。

对比方案书里"棋牌类游戏""售货机"这类案例常见的手写状态机（一个枚举 + 一堆
`switch(state)`）：`QStateMachine` 把"状态该长什么样"（`assignProperty`）和
"什么时候切换状态"（`addTransition`）分开声明，状态一多，可读性明显好于手写
`switch`。

## 代码走读

见 [`qt_state_machine.cpp`](qt_state_machine.cpp)：

1. 定义 `redState`/`greenState` 两个 `QState`，各自用 `assignProperty` 声明
   进入该状态时按钮的文本和样式；
2. `redState->addTransition(&button, &QPushButton::clicked, greenState)`，
   反向同理——点击按钮在两态间来回切换（红灯 → 绿灯 → 红灯 → ……）；
3. `machine.setInitialState(redState)` + `machine.start()` 启动状态机；
4. 离屏验证用 `QTimer::singleShot` 模拟一次 `button.click()`，观察状态确实从
   红灯切换到绿灯。

## 验证方式

```bash
QT_QPA_PLATFORM=offscreen tools/run_qt.sh qt_state_machine
```

## 练习方向（供任务卡引用）

- 加一个 `yellowState`（黄灯），改成红→绿→黄→红的三态循环，体会状态数量增加
  时 `QStateMachine` 写法的可读性优势；
- 给某个状态加一个定时器转换：`redState->addTransition(timer, &QTimer::timeout, greenState)`，
  实现"红灯持续 3 秒后自动变绿灯"（不需要用户点击）。

## 参考

- 本仓库对照：[`p03/ch06/modal_dialog.cpp`](../../../../p03/ch06/modal_dialog.cpp)
  等对话框示例里也有"根据用户操作决定下一步界面"的朴素状态切换，可以对比
  "手写 if/else" 和 "QStateMachine 声明式写法" 的差异；
- Qt 官方文档：*The State Machine Framework*（doc.qt.io，选读·需联网）
