# Fix-BUG-20260109-0001 > 适用场景:记录某个 BUG 的修复方案、影响评估、验证结果与落地信息。 ## 关联信息 - Fix ID: Fix-BUG-20260109-0001 - 关联 BUG ID: BUG-20260109-0001 - 修复目标: 修复 TextBox 在 Window 创建 / 绘制前调用 `setText()` 设置默认文本时因即时绘制导致的崩溃。 - 状态:已完成 - 负责人: 未记录 - 分支 / 版本: master / v3.0.0 ## 根因分析 - 根因: `TextBox::setText()` 将“状态更新”和“立即绘制”耦合在一起。窗口尚未 `initgraph()`、EasyX 图形上下文未就绪时,`draw()` 内部进入 `Control::saveBackground()`,调用 `SetWorkingImage()` / `getimage()` 等依赖有效图形环境的逻辑,最终崩溃。 - 触发条件: 创建 TextBox 后,在 Window 初始化 / 首次绘制前调用 `TextBox::setText()`。 - 为什么之前没发现:[可选] 常规示例多为 Window 完成初始化后再设置文本,缺少控件生命周期前置调用的最小回归用例。 - 关键证据:[可选] 调用链为 `TextBox::setText()` -> `TextBox::draw()` -> `Control::saveBackground()` -> EasyX 图形上下文相关 API。 ## 修复方案 - 修复思路: `TextBox::setText()` 改为仅执行文本赋值和脏标记更新,不再在 setter 内直接调用 `draw()`;绘制统一交给 Window / 容器重绘流程。 - 关键改动: - 移除 `TextBox::setText(std::string text)` 中的直接 `draw()` 调用。 - 保留长度裁剪、文本赋值、`dirty=true`。 - 将可视更新延后到后续统一重绘周期。 - 涉及文件 / 类 / 函数: - `TextBox.cpp` - `TextBox::setText()` - 影响的 API / 行为:[可选] 对外 API 不变;`setText()` 不再保证即时绘制。 - 关键约束 / 不变量:[可选] - setter 不得直接调用 `draw()` 或任何依赖图形上下文的 API。 - `saveBackground()` / `getimage()` / `putimage()` / `SetWorkingImage()` 只能在 Window 图形上下文就绪并进入统一绘制流程后执行。 - 回滚点 / 开关:[可选] 回退 setter 内即时绘制逻辑。 ## 影响评估 - 影响范围: TextBox 默认文本设置、程序化文本更新、绘制时序。 - 兼容性影响:有(如果外部代码依赖 `setText()` 的即时绘制副作用,需要调整为触发一次重绘或等待绘制周期) - 行为变化:有(`setText()` 语义收敛为更新状态并标脏) - 性能影响:正向或无影响,减少 setter 内重复绘制与抓屏开销。 - 回归风险: - 程序化调用 `setText()` 后,如果应用没有触发任何重绘路径,界面更新可能延迟。 - 依赖即时刷新语义的旧代码可能出现短暂视觉滞后。 ## 验证结果 - 验证步骤: 1. 构造最小复现:在 Window 创建 / `draw()` 前创建 TextBox 并调用 `setText("default")`,确认不再崩溃。 2. Window 初始化后,通过事件输入或直接调用 `setText()` 更新文本,确认后续一次重绘时文本正确显示。 3. 覆盖 INPUT / READONLY / PASSWORD 三种模式,确认长度裁剪与显示逻辑不受影响。 4. 覆盖窗口 resize,确认背景快照机制仍按既有逻辑工作,无残影或错位。 - 验证结果: PDF 历史记录标记已修复。 - 回归检查:[可选] TextBox 三模式输入与显示、背景快照保存 / 恢复 / 丢弃、Window 首次绘制、对话框打开 / 关闭强制重绘、resize 收口重绘。 - 验证证据:[可选] ## 落地信息 - Commit: 5cb59b36525cde93de83313551296c6458694110 - PR:[可选] git - 发布版本: v3.0.0 - 备注: 来源原始 Fix 记录未包含 `-XXXX` 后缀,入库时按 BUG ID 补充为 `Fix-BUG-20260109-0001`。