Files
scuc-qt-course/docs/teaching/examples/lineedit_eye_toggle/README.md
T
张宗平 01b264fe97 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>
2026-07-09 16:51:09 +08:00

102 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# QLineEdit 自绘小眼睛 / echo mode 切换(qt_lineedit_eye_toggle
Day4 上午教学示例(OUTLINE_4DAY.md Day4 上午「消息机制和事件 + 绘图事件」),**同时覆盖两个主题**:
- **组件绘制**——覆写 `paintEvent`,用 QPainter 在 QLineEdit 右侧自绘眼睛图标;
- **事件捕捉**——覆写 `mousePressEvent` / `mouseMoveEvent`,几何 hit-test 命中眼睛时切换
`echoMode`,且不阻断基类的光标定位 / 拖选。
载体是 QLineEdit 密码框:右侧一个自绘小眼睛,点击在 `Password``Normal` 间切换,并显式
处理与 QLineEdit 内置 clear button 的位置冲突。
## 三区对照(先简后深)
| 区 | 内容 | 教学作用 |
|---|---|---|
| ① echo mode 四态 | Normal / NoEcho / Password / PasswordEchoOnEdit 静态对照 | 先给 echo mode 全貌,眼睛只是切换载体 |
| ② addAction 一行版 | `addAction(QIcon, TrailingPosition)` 加眼睛,点击切换 | Qt 内置、1 行实现——「为什么还要自绘」的引子 |
| ③ 自绘版主秀 | `PasswordLineEdit` 自绘眼睛 + 「启用 clear button」复选框 | 主题落地 + clear button 避让 |
## 关键教学点
### 1. 组件绘制
- `paintEvent` **先调基类**画原生内容(文本 / 边框 / clear button),再用 QPainter 叠加眼睛。
顺序不能反——基类画完后 clear button 几何才最终确定,眼睛避让才准。
- 眼睛用 QPainter 纯代码绘制(眼眶椭圆 + 瞳孔 / 斜杠两态),无外部资源。绘制逻辑抽成自由函数
`paintEye()`,③区自绘与②区 `QIcon` pixmap 共用(DRY,且对照更直观)。
### 2. 事件捕捉
- `mousePressEvent`:命中眼睛矩形 → 切 `echoMode` + `e->accept()` + `return`**不**调基类,
否则 QLineEdit 把这次点击当光标定位);非命中 → 调基类(光标定位 / 双击选词 / 右键菜单照常)。
这是「自绘交互区与原生编辑行为共存」的核心。
- `mouseMoveEvent` + `setMouseTracking(true)`:实现 hover 高亮。**坑卡**:`mouseTracking` 默认关,
不按鼠标键就收不到 `mouseMoveEvent`hover 高亮出不来。
### 3. clear button 避让(读 clearButton 子 widget 几何)
QLineEdit 内置 clear button 的宽度随主题 / DPI / 字号变化,**不能硬编码偏移**(硬编码是反面教材,
换主题即错位)。正确做法:clear button 是 QLineEdit 的一个 `objectName=="clearButton"` 直接子 widget
Qt5 私有 `QLineEditIconButton`),用 `findChild` 读它的真实几何:
```cpp
if (QWidget* cb = findChild<QWidget*>(QStringLiteral("clearButton"),
Qt::FindDirectChildrenOnly)) {
rightEdge = cb->x() - 4; // 眼睛贴 clear button 左侧,留 4px 缝
}
```
眼睛紧贴其左侧;未启用 clear button 或无文本(clear button 不占位)时贴右边。勾选③区复选框即可实时
观察眼睛从「贴右」移到「贴 clear button 左侧」、两者不重叠。
> 为什么不用 `QStyle::subControlRect`QLineEdit 不经 QStyle 的 complex-control 绘制,
> `QStyle` 没有 `CC_LineEdit` / `SC_LineEditClearButton`,无对应 subcontrol 可查——读子 widget 是唯一可靠途径。
## 目录结构
```
lineedit_eye_toggle/
├── qt_lineedit_eye_toggle.cpp # 唯一源文件(paintEye + PasswordLineEdit + ShowcaseWidget + main
├── CMakeLists.txt # 独立顶层工程(可单独 cmake -S . -B build,不走仓库统一构建)
└── README.md # 本文档
```
## 构建与运行(Windows + MinGW 7.3.0 + Qt 5.14.2
> 必须用与 Qt 5.14.2 ABI 匹配的 mingw730_64,不可用 PATH 中更高版本的 g++。
### A. 集成构建(仓库统一构建树)
```bash
# 配置(在仓库根)
cmake -S . -B build_mw -G "MinGW Makefiles" \
-DCMAKE_PREFIX_PATH=E:/Qt/Qt5.14.2/5.14.2/mingw73_64 \
-DCMAKE_CXX_COMPILER=E:/Qt/Qt5.14.2/Tools/mingw730_64/bin/g++.exe \
-DCMAKE_C_COMPILER=E:/Qt/Qt5.14.2/Tools/mingw730_64/bin/gcc.exe
cmake --build build_mw --target qt_lineedit_eye_toggle
# 运行(GUI,点 ②③ 的眼睛、勾选 clear button 体验)
PATH=/e/Qt/Qt5.14.2/5.14.2/mingw73_64/bin:$PATH \
QT_QPA_PLATFORM_PLUGIN_PATH=/e/Qt/Qt5.14.2/5.14.2/mingw73_64/plugins/platforms \
./build_mw/docs/teaching/examples/qt_lineedit_eye_toggle.exe
# 离屏自动退出验证(不交互,退出码应为 0)
QT_QPA_PLATFORM=offscreen \
QT_QPA_PLATFORM_PLUGIN_PATH=/e/Qt/Qt5.14.2/5.14.2/mingw73_64/plugins/platforms \
PATH=/e/Qt/Qt5.14.2/5.14.2/mingw73_64/bin:$PATH \
./build_mw/docs/teaching/examples/qt_lineedit_eye_toggle.exe; echo "exit=$?"
```
### B. 独立构建(单独 cmake 工程)
```bash
cd docs/teaching/examples/lineedit_eye_toggle
cmake -S . -B build -G "MinGW Makefiles" \
-DCMAKE_PREFIX_PATH=E:/Qt/Qt5.14.2/5.14.2/mingw73_64 \
-DCMAKE_CXX_COMPILER=E:/Qt/Qt5.14.2/Tools/mingw730_64/bin/g++.exe \
-DCMAKE_C_COMPILER=E:/Qt/Qt5.14.2/Tools/mingw730_64/bin/gcc.exe
cmake --build build
PATH=/e/Qt/Qt5.14.2/5.14.2/mingw73_64/bin:$PATH \
QT_QPA_PLATFORM_PLUGIN_PATH=/e/Qt/Qt5.14.2/5.14.2/mingw73_64/plugins/platforms \
./build/qt_lineedit_eye_toggle.exe
```
> 两条路径编译同一份 `qt_lineedit_eye_toggle.cpp`,行为一致。集成路径进入仓库统一构建;
> 独立路径可把这个目录单独拷走即用(仅需本目录三文件 + 一个 Qt 5.14.x)。