将界面构建从主窗口移出,保留现有业务回调与标定路径。验证结果和完整门禁限制见 docs/architecture/studio-window-refactor-plan.zh.md。
13 KiB
Studio 主窗口分步重构计划
目的:plan。范围:apps/studio/src/orisys_studio/app_window.py 及其直接调用方。
当前架构由 Studio 架构 维护;本文件是唯一实施进度记录。
目标与约束
主窗口保留组件装配、跨功能信号连接、窗口几何及明确的关闭顺序。 按职责迁移现有实现,不增加产品功能、依赖、线程或全局状态容器。 会话、回放、布局、显示偏好和记录状态继续由现有控制器持有。 显示层只读取状态;录制与标定采样继续消费采集线程的数据,不依赖刷新频率。
启动、停止、暂停、异常处理、信号顺序及懒加载时机均属于行为保持边界。 关闭时保留预览关闭、采集回调解绑、分析取消与等待、采集和录制收尾、3D 释放的顺序。 测试和工具确实使用的旧入口可以暂留,但每一步必须说明保留原因并更新真实调用方。 不提交、不切换分支;排除已有 Autocal、测试修复文档及工作区归档修改。
顺序与验收
每步都先检查调用方及相关测试,完成后更新本计划和架构文档。 任务顺序为 S0 → S1 → S2 → S3 → S4 → S5 → S6;每一步均可独立审查。
S0:基线与计划
- 记录 HEAD、索引和已有修改,建立独立 scratch 证据目录。
- 在改动前运行状态显示与主窗口相关测试。
基线:2026-10-18,orisys-app 的 main,HEAD 433b76e。
源码为 3,181 行;StudioMainWindow 有 212 个方法,含属性访问器。
原架构文档的 2,309 行及“拆分已完成”属于历史状态。
S1:状态显示
- 新建
status_presenter.py,接收显示事实与目标控件,不接收整个窗口。 - 迁移 phase、来源摘要、标定摘要、有效性及录制统计的格式化与显示。
- 保留
_record_stats注入入口,保证已有截图工具和 UI 检查仍有效。
涉及主窗口、新 Presenter 和定向测试。验收:实时视图不显示回放标题;分析结果保持自己的
传感器身份;未知、无标定、部分轴标定仍可区分;录制关闭中不显示完成,丢失计数完整。
验证:状态 Presenter 独立测试、test_ui_smoke、test_replay_wiring 和现有 UI 检查。
S2:界面构建
- 准备
ui/window_ui.py和ui/window_menus.py,先以独立窗口验证。 - 接入
ui/window_ui.py的控件和布局构建,保持控件身份、顺序及 parent。 - 迁移菜单和 QAction 创建;由窗口显式连接功能操作。
- 迁移对应文字与主题更新,保留必要属性兼容入口。
依赖 S1。涉及主窗口、UI 模块及实际调用方;面板构建和菜单构建分两批验收。
验证:test_ui_elements、test_view_layout、test_sensor_switch_window、主题与语言检查。
3D 仍在原时机创建,启动恢复顺序及保存的布局不变。
S3:实时标定交互
- 提取
live_calibration.py的选择保存、解析、确认及提交请求。 - 文件身份和匹配规则复用
CalibrationService;对话框通过窄接口访问。 - 设备确认、记录版本及采样仍走现有记录通道。
依赖 S2。验证:test_live_calibration_dialog、test_calibration_service 及确认事件测试。
导出不等于应用,应用请求不等于设备确认,序列号不匹配的处理不变。
S4:分析配置
- 提取
analysis_setup.py的对话框、裸视频工作目录和分析服务构造。 - 迁移 reference override 的所有权,保持现有保存和取消语义。
ReplayController继续负责执行、取消、缓存及结果选择,不吸收配置逻辑。
依赖 S3 的标定选择接口。验证:test_bare_video_analysis、test_analysis_progress、
test_replay_wiring;历史录制仍使用自身 chain,取消配置不改变当前结果。
S5:运行协调与预览
- 先提取
preview_controller.py,负责设备和预览定时器生命周期。 - 再提取
activity_coordinator.py,统一按钮和快捷键的运行、暂停、停止规则。 - worker 操作通过
SessionController;关闭流程继续在窗口显式排列。
依赖 S4。两批分别验证 test_session_controller、test_pause_controls、
test_transport_review 和连接中停止、断开、异常、重复关闭场景。
普通停止保持非阻塞,退出等待资源结束;预览与采集不能争用相机。
S6:显示入口与兼容桥收尾
- 将 2D/3D 的共同交付协调归入现有
FrameView,调用方显式传入显示上下文。 - 更新测试和工具为真实控制器接口,删除已无调用方的窗口转发。
- 核对依赖方向、无循环、线程归属和文档现状;运行完整门禁。
依赖 S5。验证:test_shared_depth_scale、test_scene3d_frame_views、回放定位与
显示设置重绘测试。2D/3D 使用同一帧;实时不覆盖回放;重绘不启动新分析。
结束条件是主窗口只承担约定职责,且所有相关检查通过,不以行数作为唯一标准。
验证记录
解释器使用 .venv-build/Scripts/python.exe。定向 pytest 显式使用独立的
--basetemp 和 -p no:cacheprovider;日志位于 .scratch/studio-window-refactor/。
每个迁移步骤运行对应检查;可交付批次运行 tools/gate.ps1 -Task studio-window-refactor。
文档使用工作区 scripts/doc_lint.py 和 scripts/doc_count.py,不扩大基线。
2026-10-19:S2 接线
以 main 的 c6c16df 为基准,接入已准备的两个 UI 模块;主窗口从 3,070 行减至
2,894 行。10 个控件和 35 个菜单、action 属性保留同一对象引用;18 处菜单业务回调及
控制器绑定仍在窗口。主题与文字更新委托 UI 模块,reset 目标、pause 状态仍沿用原逻辑。
FrameView、共享 domain latch 和曲线 store 在控制器接线前绑定,偏好恢复顺序不变。 只改动窗口的构造、菜单构建、菜单勾选、文字和主题刷新五个方法;其余方法的 AST 一致, 最新标定读取、应用和关闭路径未迁移。S3–S6 保持待实施。
改动前定向检查为 46 passed;接线后加上三个集成检查为 49 passed。 覆盖控件身份、菜单单次调用、主题与语言刷新、实时与回放的 reset 目标,以及既有布局、 暂停和标定对话框。首次新增断言误将菜单与按钮的不同文案视为相同,已按原契约修正。 串行门禁的 lint 通过,UI 检查为 632 checks、0 failures;共享层为 461 passed、 18 skipped、3 deselected、15 failed,涉及 SDK 映射文件缺失及几何尺寸不一致。 Studio 在垃圾回收期间访问冲突退出,无 JUnit 报告。整套门禁未通过,原因尚未完全确认。
扩展界面检查为 131 passed、1 failed,失败是分析停止后的即时状态断言。 该用例及崩溃所在的三个布局场景,在旧、新主窗口隔离运行均为 4 passed,未复现整套异常。 旧主窗口整套对照长时间无进度后已中断,不能据此判定原因。未修改失败断言或扩大基线。 临时禁用局部主题刷新时,新增测试按预期失败;仅在测试进程注入,源码未改动。
环境为 Windows、Python 3.10.19、offscreen Qt;真实设备、可见桌面和硬件 GL 未验证。
文档检查无新增问题,原架构长段落债务仍保留。证据位于
.scratch/studio-window-refactor/20261019-095028/ 和 gate-20261019T015301Z/。
另一个进程的 Autocal 修改含暂存项,全部排除;本批六个文件未暂存,根仓库未修改。
powershell -NoProfile -ExecutionPolicy Bypass -File tools/gate.ps1 -Task studio-window-refactor -LintBase HEAD -Serial
& .\.venv-build\Scripts\python.exe -m pytest apps/studio/tests/test_ui_smoke.py apps/studio/tests/test_ui_elements.py apps/studio/tests/test_sensor_switch_window.py -m 'not timing' -o faulthandler_timeout=60 -p no:cacheprovider --basetemp=D:\orisys_ws\orisys-app\.scratch\studio-window-refactor\20261019-095028\pytest-ui-focused --junitxml=D:\orisys_ws\orisys-app\.scratch\studio-window-refactor\20261019-095028\ui-focused.xml
2026-10-19:S2 模块准备,接线延期
用户要求避开另一个进程正在修改的标定配置读取和应用路径,本批只新增模块及独立测试,
不编辑 app_window.py、现有面板、标定服务、控制器或配置文件。
基准为 main 的 a0c13c1 加当时工作区修改;读取的主窗口快照留在本批 scratch。
WindowUi 创建中央控件、四个面板及布局,提供局部主题和文字更新。
WindowMenus 创建 QAction、快捷键、菜单组和勾选初值,提供静态文字及主题/语言勾选同步。
两者均不保存偏好、不绑定业务回调,不启动设备、分析或 3D;真实控件复用现有实现。
当前主窗口仍走原来的构建路径,因此不能宣称 S2 已完成迁移。
未来接线前重新核对并行标定改动,再按顺序替换布局和菜单构建。 共享 domain latch、FrameView、曲线 store、业务信号和初始偏好恢复由窗口显式装配; 第一次呈现前完成绑定。菜单初值先于业务信号连接;reset 的目标文字、pause 状态及操作可用性 仍由现有控制器和窗口同步。兼容属性引用同一批控件,不另造重复面板。
新增 test_window_surfaces.py 和现有 test_studio_binding_purity.py 为 13 passed,
测试使用临时的空 sensor catalog,不扫描正在修改的真实配置目录。
还核对了 35 个菜单与 action 属性与起始快照一致;临时取消主题组互斥后测试能发现错误,
随后原样恢复。新增文件 lint 通过,文档检查无新增问题;主窗口与起始快照逐字节一致。
本批仅证明模块可独立使用;接线后的主窗口全套回归、真实桌面与设备验证仍待执行。
日志和 XML 位于 .scratch/studio-window-refactor/20261019-094111/,最终结果为 final.xml。
& .\.venv-build\Scripts\python.exe -m pytest apps/studio/tests/test_window_surfaces.py apps/studio/tests/test_studio_binding_purity.py -p no:cacheprovider --basetemp=D:\orisys_ws\orisys-app\.scratch\studio-window-refactor\20261019-094111\pytest-final --junitxml=D:\orisys_ws\orisys-app\.scratch\studio-window-refactor\20261019-094111\final.xml
2026-10-18:S1 接线与历史验证
2026-10-18:S0 和 S1 已实施。改动前后同一组 test_ui_smoke 与
test_replay_wiring 均为 125 passed;新增 Presenter 独立测试为 19 passed。
主窗口暂为 3,052 行;状态显示已迁出,S2–S6 尚未实施。
首次完整门禁:lint、共享层(467 passed、18 skipped、3 deselected)及 UI 检查
(632 checks、0 failures)通过;Studio 为 548 passed、19 skipped、2 failed。
失败分别是 test_adopting_a_box_result_never_flashes_the_overlay_refusal 的两次绘制,
以及 test_the_replay_view_loads_a_recording_and_scrubs_it 的录制目录缺失。
两项在重构前后隔离运行均通过;重构前主窗口的完整顺序对照为 550 passed、19 skipped。 没有修改回放实现、测试断言或失败基线来消除这些失败;其发生条件尚未确认。 当前主窗口的最终串行 Studio 复测为 550 passed、19 skipped,与旧主窗口完整对照一致。 S1 本批检查完成,S2 尚未开始;首次门禁失败报告仍保留,不改写为通过。
UI 检查虽然断言通过,日志另有 asset_rejected: this coordinator has been closed 的
异步加载回调异常;其复现条件未确认,S5 的关闭流程验收需要复核。
本批使用 Windows、Python 3.10.19 和 offscreen Qt,不能作为真实设备、可见桌面操作 或硬件 GL 验证。测试反转了标定 fallback 判断,7 项相关用例中 2 项发现错误; 随后按字节恢复源码。197 个相关源码和测试文件的 SHA-256 在最终收尾比较中完全一致。 文档门禁无新增问题;架构文档仍保留一项已登记的历史长段落债务,没有扩大基线。
实际执行的完整检查如下,工作目录为 D:\orisys_ws\orisys-app;独立日志和 XML 留在
.scratch/studio-window-refactor/20261018-200221/,首次门禁汇总位于相邻的
gate-20261018T120931Z/summary.md。这些是本地证据,未纳入版本控制。
powershell -NoProfile -ExecutionPolicy Bypass -File tools\gate.ps1 -Task studio-window-refactor
& .\.venv-build\Scripts\python.exe -m pytest apps/studio/tests -m 'not timing' -p no:cacheprovider --basetemp=D:\orisys_ws\orisys-app\.scratch\studio-window-refactor\20261018-200221\pytest-final-studio --junitxml=D:\orisys_ws\orisys-app\.scratch\studio-window-refactor\20261018-200221\final-studio.xml
并行任务将 App HEAD 从 433b76e 更新至 cf3e638,未改动本次主窗口基准;
相关回放分析修改不属于本批。
根仓库的计划索引和 inventory 登记被并行任务纳入 bf44125,根仓库目前无本批未提交修改。
本次没有执行提交、暂存或历史改写;产品仓库的五个交付文件保持未暂存。