Files
Haocode/docs/agent-handoff/evidence/P2-02.md
T
2026-09-17 16:30:02 +08:00

5.6 KiB
Raw Blame History

P2-02 证据:右侧 Bash 面板滚动条与横纵交汇角

完成日期:2026-07-21(无人值守轮次) 结论:完成。右侧任务面板的代码框(#bl_code)与两栏 section 滚动区(#bl_scroll)滚动条统一为 8px、无箭头、handle 可见且 hover;横纵交汇角用 QPlainTextEdit::corner 子控件染成代码框背景 #fbfcfe,原生亮色 corner 方块消除。所有选择器均限定在 #bl_code/#bl_scroll,未添加任何无作用域的 QScrollBar/QAbstractScrollArea 规则。

交付物

文件 改动
ui/views/main_window.py 主窗口全局 QSS 中 #bl_code 规则后插入一段完全限定作用域的滚动条 + corner 规则(QPlainTextEdit#bl_code QScrollBar:*QPlainTextEdit#bl_code::cornerQScrollArea#bl_scroll QScrollBar:*QScrollArea#bl_scroll::corner);#bl_code 原有背景/边框/圆角/文本样式一字未动
tests/diag_panel_scrollbar.py 新建:离屏测量 + 断言 + 局部截图(面板全貌、代码框 render 图、角落 4x 放大)

截图(docs/agent-handoff/evidence/):p2-02-panel.pngp2-02-outbox-render.pngp2-02-codebox-corner-4x.png

关键设计决策

  1. 作用域 = objectName 限定,零全局规则。 主窗口全局 QSS 此前没有任何 QScrollBar 规则(各弹窗/附件区各自 setStyleSheet),右侧面板因此落到原生 Windows 滚动条(带箭头、17px、亮色 corner 方块)。新增规则全部写成 QPlainTextEdit#bl_code … / QScrollArea#bl_scroll … 形式,只可能匹配右面板内的对象名,结构上不可能泄漏到其他控件。
  2. corner 用 QAbstractScrollArea::corner 子控件语法QPlainTextEdit#bl_code::corner { background-color: #fbfcfe; })——Qt 文档支持的子控件,与代码框背景同色,即 backlog「corner 与代码框背景一致」;未使用不存在的 QScrollBar::corner。section 滚动区 ::corner 置透明(其横向滚动条恒关,corner 本不显示,属保险)。
  3. 口径与仓库既有风格一致8px 厚、add-line/sub-line 置 0 隐藏箭头、#d0d0d0 handle + #a0a0a0 hover、圆角 4px——与 modern_scrollbar_qss 及附件预览区风格同源,只是作用域不同。

验证(全部显式 timeout

套件 结果 预算
tests/diag_panel_scrollbar.py(新) 18 项 ALL PASS EXIT=0 180s
tests/smoke_bash_panel.py 140 项 ALL PASS EXIT=0 240s
回归 tests/smoke_offscreen.py ALL PASS 8/8 EXIT=0 240s
回归 tests/run_tests.py 41/41 EXIT=0 300s
回归 smoke_timeline / smoke_midswitch / test_main_window_event_filter 11/11、7/7、ALL PASS,均 EXIT=0 各 ≤300s

诊断脚本断言要点(对应 backlog「完成证据」):

  • 厚度:代码框横/纵滚动条实际几何 = 8px 且 sizeHint = 8pxS1/S1b/S2/S2b);section 竖滚动条实际 = 8pxS3);
  • 箭头 extentsubControlRect(CC_ScrollBar, SC_ScrollBarSubLine) 在样式代理下 = 0(S4 三项)——即箭头子控件零尺寸;
  • corner:代码框 render() 图中,右下角 8×8 交汇块渲染出 #fbfcfe9 px)、无 (255,255,255) 亮白像素(S5c/S5d);
  • 无泄漏:未命名 QPlainTextEdit 横滚动条仍为原生口径(14px,S6);附件预览滚动条保持自身 6px sizeHintS7);
  • 截图三张落盘 evidence 目录,含角落 4x 放大图。

Windows 真机截图(backlog「完成证据」第二条):已完成(2026-09-17Windows 11 真桌面,非 offscreendiag_panel_scrollbar.py 直接运行 → EXIT=0、ALL PASS;实测代码框 H=8px V=8px、section V=8px、corner #fbfcfe 9 像素(与 offscreen 测量一致);三张截图已用真机渲染覆盖:p2-02-panel.pngp2-02-outbox-render.pngp2-02-codebox-corner-4x.png(07:20 时间戳)。运行期间生产 app 以 WebView2 在前台,diag 实例经 instance-lock 守卫自动回落 QtWebEngine,未误杀对方 WebView2 进程(T0 守卫真机验证)。Linux 真机截图仍待对应环境。

测试中发现的问题与教训

  1. offscreen 下 widget.grab()QPlainTextEdit 的文档区不填充(黑图)out_box.grab() 整块 (0,0,0),但 panel.grab() 正常。改用 ob.render(painter)(渲染到透明 QPixmap)后:文本色 #243043、边框 #e6eaf2、handle #d0d0d0、corner #fbfcfe 全部出现——样式子控件在 offscreen 下正常渲染,只有文档区背景填充缺失(离屏渲染怪癖,非产品 bug)。像素断言一律走 render(),且必须先做健全性检查(文本色/handle 色像素计数 > 0)防黑图假通过。
  2. PyQt6 API 坑(三连)
    • Qt.Vertical/Qt.Horizontal 短名已移除 → Qt.Orientation.*
    • QStyleOptionSlider(widget) 构造器未绑定(只收无参/拷贝)→ 用 QStyleOptionSlider()
    • subControlRect 参数序是 (ComplexControl, QStyleOption, SubControl, widget),且滚动条箭头子控件在 PyQt6 枚举里叫 SC_ScrollBarSubLine/SC_ScrollBarAddLine(不是 C++ 文档里的 SC_DownArrowButton);CC_ScrollBar 属于 QStyle.ComplexControl 而非 ControlElement
    • 裸控件(无样式表祖先)的 style() 是基础风格且空 option 下 subControlRect 返回 0 矩形——「原生参照」只能靠 sizeHint/实际几何(如原生横条 14px)对照,不能靠 subControlRect。
  3. 测试数据out_box 要同时出横纵滚动条,必须「超宽单行(NoWrap 触发横条)+ 足够行数(触发纵条)」,只给长单行时纵条不可见。