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.cpppaint_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 选做,量力而行)。

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