- 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>
6.1 KiB
QLineEdit 自绘小眼睛 / echo mode 切换 教学示例 —— 设计
- 日期:2026-07-08
- 对应课程:Day4 上午「消息机制和事件 + 绘图事件」(OUTLINE_4DAY.md §2 Day4 上午)
- 目标产物:
docs/teaching/examples/lineedit_eye_toggle/,交付为两种形态—— ① 仓库统一构建里的qt_lineedit_eye_toggletarget; ② 可独立cmake -S . -B build构建的单独 CMake 工程。
1. 背景与目标
需要一个 Day4 上午课堂演示示例,同时覆盖两个主题:组件绘制(paintEvent)、
事件捕捉(mousePressEvent / mouseMoveEvent)。载体是 QLineEdit 扩展——在右侧加一个
小眼睛图标,点击动态切换 echoMode(Password ↔ Normal),并显式处理与 QLineEdit
内置 clear button 的位置冲突。
选 QLineEdit 而非自造控件:密码框是「自绘内嵌图标 + 点击切换」最真实的工业场景, 且复用 QLineEdit 的文本/编辑能力,让示例聚焦在「绘制 + 事件」本身。
2. 关键设计决策
2.1 组织形态:梯度对照版
窗口分三区,先简后深,让学生看清「为什么」:
| 区 | 内容 | 教学作用 |
|---|---|---|
| ① | 4 种 echo mode 静态对照(Normal/NoEcho/Password/PasswordEchoOnEdit) | 先给 echo mode 全貌,眼睛只是切换载体 |
| ② | addAction(QIcon, TrailingPosition) 一行版 |
Qt 内置做法,1 行实现——「为什么还要自绘」的引子 |
| ③ | PasswordLineEdit : public QLineEdit 自绘版 + 「启用 clear button」复选框 |
主题落地:自绘 + 事件捕获 + clear button 避让 |
2.2 实现方式锁定:子类化 + 自绘 + 自捕获
addAction 那条路由 Qt 全权处理位置/点击/避让,碰不到绘制与事件这两个主题。
故核心交付物必须是子类化 QLineEdit、覆写 paintEvent/mouse*Event。addAction 仅作
②区对照存在。
2.3 clear button 避让:读 clearButton 子 widget 几何
QLineEdit 内置 clear button 的宽度随主题/DPI/字号变化,不能硬编码偏移(坑卡)。
clear button 是 QLineEdit 的一个 objectName=="clearButton" 直接子 widget(Qt5 私有
QLineEditIconButton),用 findChild<QWidget*>("clearButton") 读其 geometry(),眼睛紧贴
其左侧;未启用或无文本时贴右边。
注:初版误用
QStyle::subControlRect(CC_LineEdit, …, SC_LineEditClearButton),编译期即报错 ——QStyle没有这两个成员,QLineEdit 不经 complex-control 绘制,无对应 subcontrol。读子 widget 是唯一可靠途径。
2.4 眼睛图标:QPainter 纯代码绘制
- 不引入
.qrc资源(YAGNI),完全契合「组件绘制」主题。 - 两态:
closed=true(密码态)= 眼眶椭圆 + 斜杠;closed=false(明文态)= 眼眶椭圆 + 实心瞳孔。 - 绘制逻辑抽成自由函数
paintEye(QPainter*, QRect, closed, hover),③区自绘与②区QIconpixmap 共用(DRY,并让对照更明显)。 - hover 态描边加深为蓝色(
#0078D7),需setMouseTracking(true)才能在无按键时收到 move。
2.5 双形态 CMake(源文件零重复)
- 唯一源文件:
qt_lineedit_eye_toggle.cpp。 - 两个 CMake 上下文引用它:
- 独立工程:
lineedit_eye_toggle/CMakeLists.txt(手写规范版,C++17,非 Qt Creator 模板)。 - 仓库集成:
examples/CMakeLists.txt的add_teaching_example(qt_lineedit_eye_toggle lineedit_eye_toggle)。
- 独立工程:
- 零污染:顶层
CMakeLists.txt:58add_subdirectory(docs/teaching/examples)不递归, 子目录CMakeLists.txt永不被统一构建触发;examples/CMakeLists.txt无 GLOB。 不计入 README/CLAUDE.md 里「173 目标」的生成器计数。
3. PasswordLineEdit 子类要点
构造: setEchoMode(Password); setMouseTracking(true); setTextMargins(0,0,iconSize+8,0)
paintEvent: base::paintEvent 先画原生; 再 recomputeEyeRect(); QPainter 画眼睛
mousePressEvent: recomputeEyeRect(); 命中眼睛 → 切 m_passwordMode + setEchoMode + accept;
否则 base::mousePressEvent(光标定位/双击选词不受影响)
mouseMoveEvent: recomputeEyeRect(); hit-test 更新 m_eyeHover + setCursor; base 保留拖选
leaveEvent: 清 m_eyeHover 局部刷新
recomputeEyeRect: findChild("clearButton") 读其几何 → 眼睛贴其左 / 贴右
信号: passwordModeChanged(bool) 供窗口状态栏显示
关键不变量:命中眼睛时 e->accept() 并 return,不调基类——否则 QLineEdit 会
把点击当光标定位;非命中时务必调基类,保留原生编辑行为。这是「事件捕获」教学点的核心。
4. 文件清单
docs/teaching/examples/lineedit_eye_toggle/
├── qt_lineedit_eye_toggle.cpp # 唯一源文件(paintEye + PasswordLineEdit + ShowcaseWidget + main)
├── CMakeLists.txt # 独立顶层工程(手写规范版,可 cmake -S . -B build)
└── README.md # 教学点 / 目录结构 / 构建(集成+独立两条)/ 坑卡
另:docs/teaching/examples/CMakeLists.txt 注册目标 + 加入 all_teaching_examples 依赖列表。
5. 验证标准(可证伪)
- 集成构建:
cmake --build build_mw --target qt_lineedit_eye_toggle绿。 - 独立构建:
cmake -S lineedit_eye_toggle -B lineedit_eye_toggle/build ... && cmake --build绿。 - 离屏:两路径产物
QT_QPA_PLATFORM=offscreen跑 200ms 后退出码 0。 - 真实交互(本机 Qt 实跑,截图为证):③区眼睛可见;点击切
Password↔Normal; 勾选 clear button 后眼睛正确让到其左侧不重叠;hover 高亮生效。
6. 显式假设
- 眼睛用 QPainter 代码绘制,不引入资源文件(契合主题 + YAGNI)。
- 独立
CMakeLists.txt手写规范版(C++17 /cmake_minimum_required(3.16)/ 无 ANDROID 噪音), 不沿用子目录里 Qt Creator 导出的低质量模板。 - ①区 4 个对照框
setReadOnly(true)防误改;PasswordEchoOnEdit的「编辑时明文」效果在 README 注明需取消只读才能体验。 - 不提交 git(项目红线:未经请求不操作 git)。