# Day 3

### 高级控件 Model/View / 事件机制 / 文件 IO 与 JSON

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

- 模块 A（3 课时）：Model/View 架构 / 事件机制
- 模块 B（3 课时）：文件 IO / JSON 解析 → 本地数据存储案例

模块 A · 讲授 35min

## Model/View 架构 / 事件机制 讲

### Model/View 模型视图架构（教学补充） 讲

    // 模型：只管数据
    auto* model = new QStandardItemModel(this);
    model->appendRow(new QStandardItem(QStringLiteral("需求分析")));

    // 视图：只管展示，不持有数据
    auto* view = new QListView(this);
    view->setModel(model);

    // 选中状态变化 → 通知外部，模型和视图之间没有直接耦合
    connect(view->selectionModel(), &QItemSelectionModel::currentChanged, ...);

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

### 事件循环机制（复用 Day2 概念） 讲

`app.exec()` 进入的就是事件循环——鼠标点击、键盘输入、定时器 触发都会变成事件，被塞进这个循环里依次分发。今天讲的"事件过滤器"就是在 事件被分发给控件之前，插一个"拦截点"。

出处：p03/ch02/minimal_qt_app.cpp

### 自定义事件处理 / 事件过滤器 讲

    class EventLabel : public QLabel {
        Q_OBJECT
    public:
        explicit EventLabel(QWidget* p=nullptr):QLabel(p){ setMouseTracking(true); }
    protected:
        void mouseMoveEvent(QMouseEvent* event) override {
            setText(QString("Move: (%1, %2)").arg(event->x()).arg(event->y()));
        }
    };

重写 `xxxEvent` 是 Qt 事件处理的主线之一（另一条线是事件过滤器 `installEventFilter`）。出处：p03/ch09/mouse_event.cpp； 事件过滤器见 event_filter_mainwindow.cpp

模块 A · 练习 95min

## 动手：Model/View + 事件 练

#### 任务卡 1 · Model/View 换视图 练

目标
  把 `qt_model_view_basics.cpp` 里的 `QListView` 换成 `QTableView`，模型代码不改
验收标准
  编译通过，界面正常展示同一份数据，证明"同一个模型可以喂给不同视图"
基础知识 · 参考
  qt_model_view_basics.cpp · README

#### 任务卡 2 · 事件过滤器实操 练

目标
  仿 `event_filter_mainwindow.cpp`，给一个控件装事件过滤器，拦截鼠标按下事件并打印坐标
验收标准
  点击控件后终端/调试输出能看到坐标信息
基础知识 · 参考
  event_filter_mainwindow.cpp · mouse_event.cpp

模块 B · 讲授 35min

## 文件 IO / JSON 解析 讲

### 文件系统：QFile 读文本 讲

    QFile file("in.txt");
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "打开失败"; return -1; }
    while (!file.atEnd()) { qDebug() << file.readLine(); }

出处：p03/ch11/qfile_basic.cpp；结构化读写见 qtextstream_io.cpp、 qdatastream_io.cpp

### JSON 解析与写入（教学补充） 讲

    QJsonObject student;
    student["name"] = QStringLiteral("张三");
    student["score"] = 92;

    QJsonDocument doc(student);
    QByteArray bytes = doc.toJson(QJsonDocument::Indented);   // 序列化

    QJsonDocument parsed = QJsonDocument::fromJson(bytes);     // 反序列化
    QJsonObject obj = parsed.object();
    qDebug() << obj["name"].toString() << obj["score"].toInt();

出处：docs/teaching/examples/json_io/qt_json_parse_write.cpp （配套 README）—— 仓库 `p03/ch11` 的 wiki 抓取内容只有 QFile/QTextStream/QDataStream，没有 JSON， 这是本轮补写的教学补充示例；不需要 GUI，`tools/run_qt.sh qt_json_parse_write` 直接跑即可，不需要 `QT_QPA_PLATFORM=offscreen`。

模块 B · 练习 95min（本地数据存储案例，练习任务，非预建方案）

## 动手：本地数据存储小工具 练

#### 任务卡 1 · JSON 落盘 练

目标
  把 `qt_json_parse_write.cpp` 的 JSON 数据实际写入一个文件（结合 `qfile_basic.cpp` 的 `QFile` 写法），再读回来解析校验
验收标准
  程序运行后磁盘上生成一个 `.json` 文件，内容可读；重新运行程序能正确解析出 之前写入的数据
基础知识 · 参考
  qt_json_parse_write.cpp · README · qfile_basic.cpp

#### 任务卡 2 · 本地数据存储小工具 练

目标
  设计一个"学员信息"结构（姓名/成绩/标签），支持增加一条记录并追加保存到 JSON 文件， 重启程序后能读出之前保存的全部记录
验收标准
  至少能存 2 条以上记录并在重启后完整读回；数据字段不丢失
基础知识 · 参考
  docs/teaching/examples/json_io/ · qtextstream_io.cpp

## 当日产出验证

#### 现场演示

现场演示本地数据存储小工具，验证"写入 → 重启 → 读回"完整闭环。

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