Day4 教学示例补三个:QDialog 综合 / QLineEdit 小眼睛 / 文件 IO(+顶层构建注册)
- qdialog_showcase:wiki「6 对话框 QDialog」6.2–6.5 综合演示。含两套实现:
· Designer 表单版(dialog.{h,cpp,ui} + resources.qrc + source.gif,QMovie 播 GIF)
· 纯代码版(qt_dialog_showcase.cpp,单文件,QWidget 布满按钮逐个演示 QDialog 行为)
- lineedit_eye_toggle:子类化 QLineEdit,paintEvent 自绘小眼睛、mouseEvent 命中切换
echoMode,并与内置 clear button 动态避让(读 objectName=="clearButton" 子 widget 几何)。
含独立子目录 CMakeLists.txt 供单独打开(顶层 add_subdirectory 不递归)。
- file_io_demo:QFile/QTextStream/QDataStream/QFileInfo/QDir/QTextCodec/QJson 五主题
综合示例,每个按钮产出一个文件落到 demo_output/ 便于课堂手动查看。
构建注册:examples/CMakeLists.txt 用 add_teaching_example 注册前两个纯代码示例,
mandelbrot 多源文件单独 add_executable;calculator_mainwindow_qss 加 themes.qrc 与
AUTORCC;all_teaching_examples 依赖列表同步补齐。
附 lineedit_eye_toggle 设计文档(docs/superpowers/specs)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
# qt_file_io_demo —— Qt5 文件操作教学示例
|
||||
|
||||
一个 `QWidget` 布满按钮,分 5 个主题演示 Qt5 文件操作。每个按钮产生一个文件,落到
|
||||
**可执行文件同目录的 `demo_output/`** 子目录下,界面顶部 `statusLabel` 始终显示绝对路径,
|
||||
方便课堂逐个手动打开查看文件内容。
|
||||
|
||||
> 这是对仓库 `json_io`(控制台、仅内存序列化)的 GUI 补充:把 **QJson + 真实文件 I/O**
|
||||
> 与其它文件操作主题一起,放进一个可点击演示的界面。
|
||||
|
||||
## 构建
|
||||
|
||||
仓库统一构建(走 `examples/CMakeLists.txt` 的 `add_teaching_example`):
|
||||
|
||||
```bash
|
||||
cmake -S . -B build -G Ninja -DBUILD_QT_PART=ON \
|
||||
-DCMAKE_PREFIX_PATH=$PWD/.qt514/5.14.2/gcc_64 -DCMAKE_BUILD_TYPE=Debug
|
||||
cmake --build build --target qt_file_io_demo
|
||||
tools/run_qt.sh qt_file_io_demo
|
||||
```
|
||||
|
||||
单独打开(用本目录的独立 `CMakeLists.txt`):
|
||||
|
||||
```bash
|
||||
cmake -S . -B build -DCMAKE_PREFIX_PATH=<Qt5.14.2> -DCMAKE_CXX_COMPILER=<g++>
|
||||
cmake --build build
|
||||
```
|
||||
|
||||
离屏自动化验证(仿 p03 风格,200ms 自动退出、退出码 0):
|
||||
|
||||
```bash
|
||||
QT_QPA_PLATFORM=offscreen tools/run_qt.sh qt_file_io_demo
|
||||
```
|
||||
|
||||
## 界面布局
|
||||
|
||||
```
|
||||
┌─ statusLabel(显示绝对路径 + 每个演示的结果摘要)─────────────┐
|
||||
├─ ① 基础文件操作 QFile 写/读/追加、QFileInfo、QDir │
|
||||
├─ ② 字符集编码 UTF-8 / Latin-1 / GBK / UTF-16LE / 乱码对比 │
|
||||
├─ ③ 文本vs二进制 QTextStream / QDataStream / QIODevice::Text │
|
||||
├─ ④ 异常处理 Qt 返回值式 | C++ try/catch(对照) │
|
||||
├─ ⑤ QJson 文件 写 / 读 / 改写 │
|
||||
├─ [在文件管理器中打开 demo_output] [清空 demo_output] │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 各主题要点与产出文件
|
||||
|
||||
### ① 基础文件操作
|
||||
| 按钮 | 产出文件 | 要点 |
|
||||
|---|---|---|
|
||||
| QFile 写文本 | `01_qfile_write.txt` | `QTextStream` 写;**坑点:Qt5 默认 codec 是系统区域编码(中文 Windows 常为 GBK),写中文必须显式 `setCodec("UTF-8")`** |
|
||||
| QFile 读文本 | (读上一个) | 读端同样要 `setCodec("UTF-8")`,否则跨平台乱码 |
|
||||
| 追加 vs 覆盖 | `01_append.txt` | `WriteOnly` 每次清空;`Append` 在末尾追加 |
|
||||
| QFileInfo 信息 | `01_fileinfo.txt` | `exists / size / absoluteFilePath / absolutePath` |
|
||||
| QDir 列目录 | — | `entryList(QDir::Files)` 列出 `demo_output` 内文件 |
|
||||
|
||||
### ② 字符集编码
|
||||
| 按钮 | 产出文件 | 要点 |
|
||||
|---|---|---|
|
||||
| 写 UTF-8 | `02_utf8.txt` | `QString::toUtf8()`:中文每字 3 字节、ASCII 每字 1 字节 |
|
||||
| 写 UTF-8 + BOM | `02_utf8_bom.txt` | 头部 `EF BB BF`(十六进制可见) |
|
||||
| 写 Latin-1 | `02_latin1.txt` | `toLatin1()` 只能表 `U+0000~U+00FF`,中文超出变 `?` |
|
||||
| 写 GBK | `02_gbk.txt` | `QTextCodec::codecForName("GBK")`;**未装 CJK codec 插件时返回 `nullptr`,界面列出当前可用编码并给出提示**。本仓库 MinGW Qt 未含 `plugins/codecs/`,故此按钮走降级提示(这本身就是教学点);如需真正写 GBK,用 Qt Maintenance Tool 勾选安装 codecs 插件,或把 `plugins/codecs/` 拷到 Qt 的 plugins 目录 |
|
||||
| 写 UTF-16LE | `02_utf16le.txt` | 手动写 `FF FE` BOM + 每字符固定 2 字节(低字节在前) |
|
||||
| 乱码:错码读回 | (读 `02_utf8.txt`) | UTF-8 字节用 Latin-1 强解 → mojibake,说明「读写编码须一致」 |
|
||||
|
||||
> 用编辑器(VS Code / Notepad++)切换编码打开这些文件,可直观看到「同一段中文在不同编码下的字节差异」与乱码成因。
|
||||
|
||||
### ③ 文本方式 vs 二进制方式
|
||||
| 按钮 | 产出文件 | 要点 |
|
||||
|---|---|---|
|
||||
| 文本写结构 | `03_struct_text.txt` | `QTextStream` 写 `name=张三 / age=20 / score=95.5`:可读但格式松散 |
|
||||
| 二进制写结构 | `03_struct_bin.dat` | `QDataStream` 写 `qint32 + double + QString`:紧凑、带类型、可精确还原(程序内立即读回验证) |
|
||||
| 对比大小 | — | `QFileInfo` 报告两文件字节数;用十六进制工具看 `.dat` 内部布局 |
|
||||
| QIODevice::Text 换行 | `03_nl_text.txt` / `03_nl_bin.txt` | Windows 下 `Text` 标志把 `\n` 转 `\r\n`,不加则原样 `\n`;Linux 下两者相同 |
|
||||
|
||||
> `QDataStream` **务必 `setVersion(Qt_5_14)`**,否则 Qt 升级后二进制格式可能不兼容。
|
||||
|
||||
### ④ 异常与错误处理(两范式对照)
|
||||
| 按钮 | 要点 |
|
||||
|---|---|
|
||||
| Qt: 打开不存在文件 | **Qt 范式**:`open()` 返回 `false` + `error()` / `errorString()`,不抛异常 |
|
||||
| Qt: 只读模式写 | 只读 `QFile` 调 `write()` 返回 `-1` + `errorString()` |
|
||||
| C++: ifstream 异常 | **C++ 范式**:`in.exceptions(failbit\|badbit)` 后打开失败抛 `std::ios_base::failure`,`try/catch` 捕获 |
|
||||
| C++: throw + catch | 自定义异常 + `catch` 顺序(派生类在前、基类在后) |
|
||||
| JSON: 损坏解析 | `04_broken.json`:`QJsonDocument::fromJson` 不抛异常,用 `QJsonParseError` 拿出错偏移与描述 |
|
||||
|
||||
> 核心对照:**Qt 几乎不用 C++ 异常**,错误经返回值/API 暴露;标准库流默认也不抛,需显式开启。
|
||||
> 教学 LLVM 式「异常 vs 返回值」两种错误处理哲学的绝佳切入点。
|
||||
|
||||
### ⑤ QJson 文件读写
|
||||
| 按钮 | 产出文件 | 要点 |
|
||||
|---|---|---|
|
||||
| 写 JSON 文件 | `05_student.json` | `QJsonObject` + `QJsonArray` → `QJsonDocument::toJson(Indented)` → 写文件 |
|
||||
| 读 JSON 文件 | (读上一个) | `fromJson` → `object()` → 按键取值,`toArray()` 遍历数组 |
|
||||
| 修改后回写 | (覆盖上一个) | 改 `score`、增 `grade`、删 `enrolled`,覆盖回写 |
|
||||
|
||||
## demo_output 在哪?
|
||||
|
||||
`QCoreApplication::applicationDirPath() + "/demo_output"` —— 即**可执行文件旁边**。
|
||||
`tools/run_qt.sh` 运行时通常在 `build/` 下,所以路径形如 `build/qt_file_io_demo` 同级。
|
||||
界面底部「在文件管理器中打开 demo_output」按钮可一键定位。
|
||||
|
||||
## 相关课程点
|
||||
|
||||
对应「C++ 方向 Day3」文件与数据格式章节;与 `json_io`(控制台 QJson 内存演示)、
|
||||
`p03/ch11`(wiki 的 QFile/QTextStream/QDataStream)互为补充。
|
||||
Reference in New Issue
Block a user