# Day 4

### 2D 图形绘制 / 多线程 / 动画框架与状态机

C++/Qt 方向实训 · 第 4 / 5 天 · 讲:练 ≈ 1:2.7

- 模块 A（3 课时）：2D 绘图 / 多线程
- 模块 B（3 课时）：动画框架 / 状态机 → 交互式小游戏案例

模块 A · 讲授 35min

## 2D 绘图 / 多线程 讲

### 绘图：QPainter 讲

    void paintEvent(QPaintEvent*) override {
        QPainter painter(this);
        painter.drawLine(QLine(10, 10, 200, 10));
        painter.drawRect(QRect(10, 30, 100, 50));
        painter.drawEllipse(QRect(150, 30, 100, 80));
    }

所有绘制都发生在 `paintEvent` 里，由 Qt 在需要重绘时自动调用。 出处：p03/ch10/qpainter_basic.cpp；绘图设备 （`QImage`/`QPixmap`/`QPicture`）见 paint_device_qimage.cpp、 paint_device_pixmaps.cpp

### QThread 多线程（教学补充） 讲

    class Worker : public QObject {
        Q_OBJECT
    public slots:
        void process() {
            qint64 sum = 0;
            for (int i = 1; i <= 1000000; ++i) sum += i;
            emit resultReady(sum);   // 排队连接自动把结果带回主线程
        }
    signals:
        void resultReady(qint64 result);
    };
    worker.moveToThread(&workerThread);   // 官方推荐写法：worker-object + moveToThread
    connect(&workerThread, &QThread::started, &worker, &Worker::process);

出处：docs/teaching/examples/qthread_worker/qt_thread_worker.cpp （配套 README）—— 仓库 `p03/` 的 wiki 抓取内容没有多线程，这是本轮补写的教学补充示例，已验证跑通。

模块 A · 练习 95min

## 动手：绘图 + 多线程 练

#### 任务卡 1 · 画一个简单图形界面 练

目标
  仿 `qpainter_basic.cpp`，在 `paintEvent` 里画一个组合图形 （如棋盘格/仪表盘刻度）
验收标准
  编译通过，离屏或 X 环境下能看到图形正确绘制（可截图验证）
基础知识 · 参考
  p03/ch10/qpainter_basic.cpp

#### 任务卡 2 · 感受多线程不卡界面 练

目标
  把 `qt_thread_worker.cpp` 里的耗时计算换成一个更长的循环或 `QThread::msleep`，观察主线程/事件循环没有被卡住
验收标准
  能说清楚"如果把这段计算直接放主线程会发生什么"（界面无响应），并解释 `moveToThread` 起的作用
基础知识 · 参考
  qt_thread_worker.cpp · README

模块 B · 讲授 35min

## 动画框架 / 状态机 讲

### QPropertyAnimation 动画（教学补充） 讲

    auto* anim = new QPropertyAnimation(button, "geometry", &window);
    anim->setDuration(800);
    anim->setStartValue(QRect(10, 10, 100, 30));
    anim->setEndValue(QRect(180, 140, 120, 40));
    anim->setEasingCurve(QEasingCurve::OutBounce);
    anim->start(QAbstractAnimation::DeleteWhenStopped);

出处：docs/teaching/examples/property_animation/qt_property_animation.cpp （配套 README）

### QStateMachine 状态机（教学补充） 讲

    auto* redState = new QState(&machine);
    auto* greenState = new QState(&machine);
    redState->assignProperty(&button, "text", QStringLiteral("红灯：禁止通行"));
    greenState->assignProperty(&button, "text", QStringLiteral("绿灯：允许通行"));
    redState->addTransition(&button, &QPushButton::clicked, greenState);
    greenState->addTransition(&button, &QPushButton::clicked, redState);
    machine.setInitialState(redState);
    machine.start();

出处：docs/teaching/examples/state_machine/qt_state_machine.cpp （配套 README）—— `QStateMachine`/`QState` 属于 QtCore，不需要额外模块。以上两个 （动画、状态机）都是仓库 `p03/` 原本没有的教学补充示例，已离屏验证跑通。

模块 B · 练习 95min（交互式小游戏案例，练习任务，选做，非预建方案）

## 动手：动画 + 状态机小游戏 练

#### 任务卡 1 · 动画 + 状态机组合 练

目标
  把动画和状态机组合到同一个窗口——例如按钮在"红灯"状态时禁止移动，"绿灯"状态时 点击才触发动画
验收标准
  状态切换正确（红灯不触发动画，绿灯触发动画）；动画播放完整不报错
基础知识 · 参考
  property_animation/ · state_machine/

#### 任务卡 2（选做）· 简易反应力小游戏 练

目标
  结合任务卡 1 + 鼠标事件（Day3 `mouse_event.cpp`）+ 多线程计时 （Day4 `qt_thread_worker.cpp`），做一个"状态变化后限时点击"的最小交互游戏
验收标准
  游戏至少有"开始→进行中→结束"三个可辨识状态，计时或计分逻辑不崩溃
基础知识 · 参考
  上述三个教学补充示例 + mouse_event.cpp

## 当日产出验证

#### 现场演示

    QT_QPA_PLATFORM=offscreen tools/run_qt.sh <target>
    # 有 X 环境：去掉 QT_QPA_PLATFORM=offscreen 直接看窗口

分组演示动画+状态机组合小工具（任务卡 2 选做，量力而行）。

返回目录 · ← 上一天 · 下一天 →