# Studio 外壳:视图与关闭流程 这份文档记录主窗口的两件"外壳"行为:三个顶层视图如何切换面板,以及窗口关闭后进程 如何回到命令行。两者都不属于记录通道,但都会直接影响可用性。 --- ## 1. 三个顶层视图 = 同一窗口的三套布局 品牌轨上的三个导航项不打开新窗口,而是切换主窗口的布局 (`StudioMainWindow._apply_view_preset`,预设在 `VIEW_PRESETS` / `VIEW_SPLITTER_SIZES`): | 视图 | 面板 | 曲线模式 | 分割比例(3D, 2D, 曲线, 标定) | |---|---|---|---| | 实时监测 `live` | 2D 图像 + 力曲线(+ 手指三维) | 跟随实时 | `0, 360, 1080, 0` | | 历史回放 `replay` | 2D 图像 + 力曲线 | 进入全程浏览 | `0, 320, 1120, 0` | | 标定 `calibration` | 标定面板 + 力曲线 | 不变 | `0, 0, 560, 880` | | 自由 `custom`(启动默认) | 由视图菜单决定 | 不变 | 用户在分割条上摆的位置 | - **为什么标定视图给标定面板 880 px**:六列诊断表头加九个动作按钮,在 300–400 px 的 三栏布局里必然被挤压(原来的症状就是按钮文字被切成「排 除」「设为验证点」)。面板自身 还有纵向滚动区,窗口再矮也够得到「应用到标定」。 - **为什么导航不再自动打开回放对话框**:回放对话框(视频 + 离线深度重算 + 同一游标)仍 从「文件」菜单打开;导航的职责是把"看历史"这件事在主界面里摆好——全程浏览 + 2D 图像, 立刻可以拖时间轴。 - **`custom` 不点亮任何导航项**:手工摆出来的布局不属于三个视图中的任何一个,点亮一个 会误报状态。 - **`视图 → 标定面板` 与「标定」导航是同一个开关**:勾上进入标定视图,取消回到实时视图。 不允许出现"面板已隐藏但导航还亮着"。 回放对话框的三颗按钮曾经完全没有文字——`PlaybackDialog.retranslate()` 写好了却从没被 调用过。现在它在 `__init__` 末尾调用一次(`test_the_playback_dialog_labels_its_buttons` 守住这一点)。 --- ## 2. 关闭流程:窗口关掉后进程必须回到命令行 关闭顺序(`StudioMainWindow.closeEvent` → `main()`): 1. `closeEvent`: - 先摘掉记录通道的 sink,避免正在收尾的采集线程继续持有窗口; - `_stop_run(reason="user_stop", wait=True)`:阻塞地释放设备; - `_stop_recording(wait=True)`:写出 `session.json` 并关闭 MP4/CSV; - `_persist_prefs()`:保存窗口几何、分割比例、视图与各项开关。 2. `app.exec_()` 返回后,`main()` **立刻结束进程**: ```python code = int(app.exec_()) logging.shutdown() for stream in (sys.stdout, sys.stderr): try: stream.flush() except Exception: pass os._exit(code) ``` **为什么用 `os._exit`**:相机 SDK 与 OpenCV 各自持有原生线程与句柄,正常返回会在它们之上 再跑一遍解释器收尾(模块销毁、DLL 卸载),进程就卡在那里——症状正是"命令行不会完全退出"。 所有需要落盘的东西在 `closeEvent` 与 `logging.shutdown()` 里已经写完,这里跳过的只是 "已经没有东西可写的库"的析构。 `tools/ui_check.py` 的 `clean shutdown` 段在子进程里跑真实的 `main()`,用定时器关掉窗口 并断言进程在 45 秒内以 0 返回(实测约 2 秒),所以这条路径有回归保护。 --- ## 3. 复核方式 ```powershell $py = "D:\orisys_ws\orisys-app\.venv-build\Scripts\python.exe" $env:PYTHONPATH = "D:\orisys_ws\orisys-app\shared\src;D:\orisys_ws\orisys-app\apps\studio\src" cd D:\orisys_ws\orisys-app\apps\studio & $py tools/ui_check.py # 含 top area / instrument panels / clean shutdown & $py tools/ui_snapshot.py --demo --preset calibration --out outputs/_snap_calibration.png & $py tools/ui_snapshot.py --demo --scene recording --out outputs/_snap_recording.png ```