Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 9 additions & 10 deletions todo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,33 @@

```
入门 137✅ · 进阶 134✅ · 专家 2/102(01·02 COW 已审结,见 expert.md)
实例库 widget 2/13(status-led✅ + toggle-switch✅),app/model/industrial
实例库 widget 13/13 ✅收齐(status-led✅ + toggle-switch✅ + circle-progress✅ + speed-meter✅ + range-slider✅ + line-chart✅ + editable-table✅ + checkbox-tree✅ + checkbox-list✅ + log-viewer✅ + password-edit✅ + ip-edit✅ + fade-animation✅),app/model/industrial 骨架已立
examples 275✅ · 基建 P0✅ 基本清完
```

## 接力点(下次会话从这里接 · 2026-06-16 更)
## 接力点(下次会话从这里接 · 2026-06-25 更)

- **已合入 main(f8349b0)**:status-led 中等档标杆(PR#10) · D3 sweep「需要注意的是」×30 + 死链(PR#11) · Task A 风格违例(值得注意的是/一般来说/大概) · toggle-switch 控件 + 双文档
- 工作区干净、本地 `main == origin/main`
- **下一步二选一**:
- ① 专家篇 `01-qobject-meta-system`(慢·审核门限·一次一篇·A/B 双 Agent 取证,见 [.claude/production-paradigm.md](../.claude/production-paradigm.md) §2)
- ② 实例库续 `circle-progress`(widget 撑场批)或破 `app/image-viewer`(快·D2 放量·照 status-led/toggle-switch 模板,构建门 + 双文档)
- **分支 `instance/widget-painter-batch`(从 main 切·本机已 commit 未 push)**:widget 栏四批共 11 件全收齐——自绘链 4(circle-progress/speed-meter/range-slider/line-chart) + model/view 2(editable-table/checkbox-tree) + input/display 3(checkbox-list/log-viewer/password-edit) + 收尾 2(ip-edit/fade-animation)。每件 STATIC 库+demo+构建门绿(零 warning)+offscreen 冒烟+Full 导览+Handbook。另含两处修复:**speed-meter 指针角度 bugfix + 小尺寸藏标签**、**editable-table 步长+填宽**。②d 批起 code Agent 预 clang-format(行号不漂、提交一把过)。**widget 栏 13/13 完成,待作者抽审放量**。
- **已合入 main(f8349b0)**:status-led 标杆 · toggle-switch 控件 + 双文档(上一批)
- 工作区:分支上 11 件 + 2 修复 + todo 更新;`main == origin/main`;widget 栏 13/13 完成
- **下一步(审完合入后)**:widget 栏已收齐,转战 **app 栏破零**(image-viewer/sqlite-browser/serial-tool)或 model 栏放量(其余 17 照 undo-redo 范式);专家层在 `expert/meta-object-system` 分支另线推进(5 篇未并入 main,README 专家行待合并后统一)
- **挂账**:05-other-modules ~25 篇缺踩坑段——按「不编坑」原则,等真写到该模块再补真坑(memory: no-fabricated-pitfalls)
- ⚠ **作者会在终端并行 commit/push/merge**(本会话发生过):AI 改文件前先 `git status`;提交 / push 全归作者;commit / PR **不带任何 AI 署名**(memory: no-ai-attribution / user-handles-all-pushes)
- ⚠ **作者会在终端并行 commit/push/merge**:AI 改文件前先 `git status`;提交 / push 全归作者;commit / PR **不带任何 AI 署名**(memory: no-ai-attribution / user-handles-all-pushes)

## 工作区 → 文件

| 工作区 | 文件 | 内容 | 当下 |
|---|---|---|---|
| 专家层 | [expert.md](expert.md) | 102 篇源码拆解(每篇带 qt_src 行号证据) | ✅ 01·02 COW 已审结 → 下一篇 qobject |
| 实例库 | [instance-library.md](instance-library.md) | widget/app/model/industrial 成品 + 两套文档 | widget 2/13(status-led + toggle-switch✅)· app/model/industrial |
| 实例库 | [instance-library.md](instance-library.md) | widget/app/model/industrial 成品 + 两套文档 | widget 6/13(+circle/speed/range/line✅·分支待审)· app/model/industrial 骨架已立 |
| 基建 | [infra.md](infra.md) | P0/P0.5/P1/P4 + widget 化简 + 地基债 | ✅ P0 基本清完 · 剩 sidebar/结构漂移 |
| embedded | [embedded.md](embedded.md) | Layer1 公共基础 + Layer2 板级 | ⚠ 生产方式待定 |
| 延后 | [parked.md](parked.md) | community/translation/interactive/CI门… | 不投入 |

## 当下优先

- 专家层:01·02 已审结 → 下一篇 01-qobject-meta-system(D1·审核门限·一次一篇)
- 实例库:widget 2/13 → 续 circle-progress;app/model/industrial 三栏零起步待破
- 实例库:widget 6/13(自绘链 4 件待审,分支 instance/widget-painter-batch)→ 续 ⑦editable-table 或破 app/image-viewer;app/model/industrial 骨架已立待成品化
- 基建:P0✅ 基本清完(死链 + 需要注意的是×30 + 风格违例已入 main)→ 剩 专家 sidebar 收敛 + 入门结构漂移

## gate
Expand Down
10 changes: 7 additions & 3 deletions todo/instance-library.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
6. industrial 链接 widget 库 .so 复用(speed-meter/circle-progress/line-chart 先落地)

### widget 栏(13·每族代表·自绘递进链)
路径 `widget/<家族>/<控件名>/`。①status-led✅中等档标杆(颜色过渡+呼吸+Q_PROPERTY全+双文档pilot待验格式) ②toggle-switch✅(2026-06-16,滑动动画+拖动/点击+Q_PROPERTY配色+双文档) ③circle-progress ④speed-meter ⑤range-slider ⑥line-chart(纯QPainter) ⑦editable-table ⑧checkbox-tree ⑨checkbox-list ⑩log-viewer ⑪password-edit ⑫ip-edit(P1) ⑬fade-animation(P1)。未覆盖9族首波不碰:calendar/datetime/opengl/specialized/network-widget/data-display/multimedia/map/print。
路径 `widget/<家族>/<控件名>/`。①status-led✅中等档标杆(颜色过渡+呼吸+Q_PROPERTY全+双文档pilot待验格式) ②toggle-switch✅(2026-06-16,滑动动画+拖动/点击+Q_PROPERTY配色+双文档) ③circle-progress✅(2026-06-25·value/progress解耦+drawArc) ④speed-meter✅(2026-06-25·动画指针+刻度) ⑤range-slider✅(2026-06-25·双柄拖拽) ⑥line-chart(纯QPainter·2026-06-25) ⑦editable-table✅(2026-06-25·委托校验+数据往返) ⑧checkbox-tree✅(2026-06-25·三态+父子联动) ⑨checkbox-list✅(2026-06-25·QListWidget勾选+批量守卫) ⑩log-viewer✅(2026-06-25·级别染色+裁旧) ⑪password-edit✅(2026-06-25·显隐+强度) ⑫ip-edit✅(2026-06-25·4段跳焦+0-255校验) ⑬fade-animation✅(2026-06-25·OpacityEffect淡入淡出)。**widget 栏 13/13 收齐**。未覆盖9族首波不碰:calendar/datetime/opengl/specialized/network-widget/data-display/multimedia/map/print。

### app 栏(7旗舰+1拉伸·撑「真库不是片段」)
路径 `app/<类目>/<应用名>/`。image-viewer★5 / sqlite-browser★5 / json-editor★4 / network-tool★4-5 / cpu-memory-monitor★4 / serial-tool★4-5(补入·嵌入式最高频) / tetris★4-5 / ~~audio-visualizer~~(拉伸·须先做模拟数据发生器)。
Expand All @@ -42,8 +42,12 @@
> **[格式 gate]** ✅ status-led 已产 Full 导览 + Handbook(入口+01/02/03+troubleshooting)两套样板(2026-06-14,落 `tutorial/engineering/instances/widget/status-led/`)→ 待作者验格式放量后续

①✅已完成:status-led 基建化简(降C++17+重命名+STATIC库) + 深度改造(中等档:颜色过渡 QPropertyAnimation + 呼吸 QVariantAnimation + Q_PROPERTY 全 + minimumSizeHint) + 双文档 pilot(成品导览 + 手搓手册 5 文件) → 作者验过格式再放量
②✅toggle-switch 已落(2026-06-16,代码+构建门+冒烟+Full+Handbook双文档) → 撑场批续:circle→speed-meter→line-chart + image-viewer/sqlite-browser/serial-tool
③覆盖批:password/ip/range-slider/editable-table/checkbox-tree/list/log-viewer/fade + json-editor/network-tool/cpu-mem
②✅toggle-switch 已落(2026-06-16,代码+构建门+冒烟+Full+Handbook双文档)
②b✅自绘链撑场批(2026-06-25·分支 instance/widget-painter-batch):circle-progress+speed-meter+range-slider+line-chart 四件,全 STATIC 库+demo+构建门绿(零warning)+offscreen冒烟+Full导览+Handbook 5文件。Workflow 并行产(speed/range/line),circle-progress 因 429 限流挂→手补。待作者抽审放量
②c✅model/view 批(2026-06-25·同分支):editable-table(委托校验+数据往返)+checkbox-tree(三态+父子联动) 两件,全 STATIC 库+demo+构建门绿(零warning)+offscreen冒烟+Full+Handbook。Workflow 并行产(本轮无 429)。待作者抽审
②d✅input/display 批(2026-06-25·同分支):checkbox-list(QListWidget勾选+批量守卫)+log-viewer(QPlainTextEdit级别染色+裁旧)+password-edit(显隐+强度) 三件,全 STATIC 库+demo+构建门绿+offscreen冒烟+Full+Handbook。本批起 code Agent 预 clang-format,行号不漂+提交一把过。待作者抽审
②e✅widget 收尾批(2026-06-25·同分支):ip-edit(4段跳焦+0-255校验)+fade-animation(QGraphicsOpacityEffect淡入淡出) 两件(P1 也做了),全 STATIC 库+demo+构建门绿+offscreen冒烟+Full+Handbook。**widget 栏 13/13 全部完成**。待作者抽审
③app/model 放量:json-editor/network-tool/cpu-mem(widget 栏 ⑫⑬ 已完成见②e,widget 栏收齐)
④✅model reference 骨架已落(2026-06-16):undo-redo-framework 库式骨架(`move_command` STATIC + demo) + 三范式已定 → 其余 17 照范式放量
⑤收尾:tetris;audio-visualizer(须先模拟数据发生器)
⑥industrial pilot:widget 链落地后→hmi-dashboard 成品化(骨架已立,复用契约见下)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
title: "Step 1:组合 QListWidget 骨架 + addItem 装复选框"
description: "继承 QWidget 内含 QListWidget 成员,构造 new 出来 parent=this 托管,addItem 用 setFlags 装复选框、setCheckState 设初值。这步先不接信号。"
---

# Step 1:组合 QListWidget 骨架 + addItem 装复选框

← [手册首页](./index.md) · 下一步 [Step 2 itemChanged + 状态汇总](./02-itemchanged-and-collect.md) →

## Step 1:组合 QListWidget 骨架 + addItem 装复选框

### 目标

屏幕上出现一张**带复选框的扁平清单**,每项前面一个方框,能手动勾上/取消。这一步**先不接 itemChanged**——纯粹是「每项一个独立复选框」的原始状态,勾选互相独立、没有任何联动或转发。信号转发是下一步的事。

### 提示

- 继承 `QWidget`,加私有成员 `QListWidget* list_`(头里前向声明 `class QListWidget;` 就够,避免头里拖进重头文件)
- 构造里 `list_ = new QListWidget(this)`——`this` 当 parent,交给对象树托管,析构自动回收;顺手 `setUniformItemSizes(true)` 提升绘制性能
- new 一个 `QVBoxLayout(this)`,`addWidget(list_)`,`setContentsMargins(0,0,0,0)` 去白边,让列表填满本控件
- 写 `QListWidgetItem* addItem(const QString& text, bool checked = false)`:
- `auto* item = new QListWidgetItem(text, list_)`——构造时把 `list_` 当 parent,挂进列表
- `item->setFlags(item->flags() | Qt::ItemIsUserCheckable)`——**用或运算加上** `ItemIsUserCheckable`,保留默认的 `ItemIsEnabled|ItemIsSelectable`,别把默认标志全冲掉
- `item->setCheckState(checked ? Qt::Checked : Qt::Unchecked)` 设初值
- 这一步**先不连 itemChanged**,纯挂节点。这一步你能看到一张每项带可勾选复选框的清单就算成功

### 关键认知

- **`ItemIsUserCheckable` 是「显示复选框」的开关**:不加这个标志,`setCheckState` 设了状态也不显示方框——很多新手卡在这里,以为是 `setCheckState` 写错了,其实是 flags 没装。`setFlags` 要用「或上」而非「赋值」,否则会丢掉默认的 enabled/selectable
- **`setCheckState` 会触发 itemChanged**:即便这一步没连槽,它也会发信号——只是没人接。下一步连了槽就要小心初始化期回灌,到时候 `blockSignals` 临时挡一下

### 检查点

跑出来是一张每项带可勾选复选框的扁平清单,勾哪个是哪个、互不影响 = 骨架对了。这一步不接信号是**正常的**,转发是下一步的事。

> QListWidget / QListWidgetItem 不熟?[QListWidget 入门](../../../../../beginner/03-qtwidgets/46-qlistwidget-beginner.md)、进阶 [Model/View 进阶](../../../../../advanced/03-qtwidgets/03-model-view-advanced.md)。对象树托管机制看 [QObject 与元对象系统](../../../../../beginner/01-qtbase/01-qobject-meta-system-beginner.md)。

### 对照答案

- 构造 + 布局组合骨架:`src/checkbox_list.cpp:15-22`
- addItem 装复选框(setFlags 或上 ItemIsUserCheckable):`src/checkbox_list.cpp:28-38`
- 头文件前向声明 + 成员声明:`include/checkbox_list.h:17` / `:94`

---

下一步:[Step 2 接 itemChanged 转发 checkedChanged + 状态汇总](./02-itemchanged-and-collect.md)。
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
title: "Step 2:itemChanged 槽 + 状态汇总 checkedTexts/checkedItems"
description: "连 itemChanged,onItemChanged 去重+边界后转发为 checkedChanged;写 checkedTexts/checkedItems 按列表顺序收已勾选项。这一步先把单项转发跑通。"
---

# Step 2:itemChanged 槽 + 状态汇总 checkedTexts/checkedItems

← [Step 1](./01-skeleton-and-additem.md) · [手册首页](./index.md) · 下一步 [Step 3 批量守卫 + 收尾](./03-batch-guard-and-polish.md) →

这一步把勾选变化转发出去,再补上「把勾选结果收出来」的汇总 API。诀窍在分清两条路:用户点击的勾选要转发,程序化批量改写(下一步才加)要挡住——这一步先把「转发」和「汇总」两件事跑通,批量守卫留到 Step 3。

## Step 2:itemChanged 槽 + 状态汇总

### 目标

连上 `QListWidget::itemChanged`,写 `onItemChanged(QListWidgetItem* item)`:去重 + 空指针边界后,转发为更易用的 `checkedChanged(item, bool)`——外部业务连这个信号就行,不用自己再去读 `checkState`。再写 `checkedTexts()` / `checkedItems()` 两个状态汇总方法,按列表顺序把已勾选项的文本/指针收出来。

### 提示(按顺序)

1. **连信号**:构造里 `connect(list_, &QListWidget::itemChanged, this, &CheckboxList::onItemChanged)`,用函数指针语法别用 SIGNAL/SLOT 宏
2. **`onItemChanged(QListWidgetItem* item)`**:入口先 `if (item == nullptr) return;`(边界),再 `emit checkedChanged(item, item->checkState() == Qt::Checked)`——把 `Qt::CheckState` 折成 `bool`,外部用起来更顺手
3. **声明信号**:`signals: void checkedChanged(QListWidgetItem* item, bool checked);`
4. **`QStringList checkedTexts() const`**:先 `list_->count()` 拿总数、`result.reserve(n)` 预分配;`for` 遍历每项,`item != nullptr && item->checkState() == Qt::Checked` 就 `result.append(item->text())`;空列表直接返回空 `QStringList`
5. **`QList<QListWidgetItem*> checkedItems() const`**:同上,但 append 的是 `item` 指针而非 `text()`
6. **两个方法都要判 `list_ == nullptr`** 早返回空容器——防御性,构造失败时也不崩

### 关键认知

- **itemChanged 不区分用户点击 vs 程序改写**:这是 Qt Item View 的既定行为。这一步只有 `addItem`(初始化期局部守卫)和用户点击会触发,问题不大;但下一-步加批量方法后,程序化 `setCheckState` 也会走这条链——所以 Step 3 要给批量方法加 `blockSignals` 守卫。这一步先把转发跑通,心里记着「程序化改写也会进来」
- **汇总按列表顺序遍历,不用 findItems**:`checkedTexts`/`checkedItems` 要保证输出顺序 = 列表显示顺序,所以用索引 `for` 遍历 `list_->item(i)`,别用 `findItems` 或迭代器——顺序和 `reserve` 预分配的简单性最重要
- **状态用 `==` 比较而非位运算**:本件只用两态,`checkState() == Qt::Checked` 足够;checkbox-tree 才会碰 PartiallyChecked 需要更细的判断

### 检查点

手动勾几个框,外部连 `checkedChanged` 的槽能收到 `(item, true/false)` = 转发对了;调 `checkedTexts()` 返回的文本列表和你勾的完全一致、顺序也和列表显示顺序一致 = 汇总对了。这一步还没批量方法,`Check all` 按钮做不出来是正常的——下一步补。

> 信号槽机制不熟?[信号与槽](../../../../../beginner/01-qtbase/02-signal-slot-beginner.md)。QListWidget 遍历与状态读取看 [QListWidget 入门](../../../../../beginner/03-qtwidgets/46-qlistwidget-beginner.md)。

### 对照答案

- itemChanged 连接:`src/checkbox_list.cpp:25`
- onItemChanged 转发 checkedChanged:`src/checkbox_list.cpp:178-184`
- checkedChanged 信号声明:`include/checkbox_list.h:86`
- checkedTexts 顺序汇总:`src/checkbox_list.cpp:109-123`
- checkedItems 顺序汇总:`src/checkbox_list.cpp:125-138`

---

下一步:[Step 3 给批量方法加 blockSignals 守卫 + Q_PROPERTY 收尾](./03-batch-guard-and-polish.md)。
Loading
Loading