Files
orisys-app/docs/architecture/studio-window-refactor-plan.zh.md
T
ykcheungab d477a4d8b7 接入 Studio 控件与菜单构建模块
将界面构建从主窗口移出,保留现有业务回调与标定路径。验证结果和完整门禁限制见 docs/architecture/studio-window-refactor-plan.zh.md。
2026-10-19 10:14:58 +08:00

13 KiB
Raw Blame History

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,根仓库目前无本批未提交修改。 本次没有执行提交、暂存或历史改写;产品仓库的五个交付文件保持未暂存。