35e86ec1f7
- What: 品牌条 40→28px 并加 实时监测/历史回放/标定 导航;导航改为切换主界面三套布局(实时=2D图像+曲线、回放=自动全程浏览、标定=标定面板 880px+曲线,2D 图像整体缩小);传感器选择(传感器 / 传感器配置 两个带 tooltip 的下拉 + 产品徽标)移到状态轨最左侧,记录模式移入设置区;新增 RecordStatusChip(记录中时长、丢帧、写入异常)与「同一时刻只有一个实心按钮」(新增 dangerOutline 描边危险样式);三轴读数移到曲线上方(16pt 等宽)、只保留最下方时间轴、网格淡化、全程浏览条可拖动;三轴配色统一为蓝/橙/绿并把语义色对比度审计扩展到 toolbar_bg;箭头页脚显示放大倍率与有效区域,深度模式才显示色条与范围;左侧面板改名「2D 图像」且固定显示图像宽高比;标定面板加纵向滚动区、九按钮分两行、六列表头 ResizeToContents;PlaybackDialog 补上从未调用的 retranslate;main() 在事件循环结束后 flush 日志并 os._exit,避免设备 SDK 原生线程把进程挂在解释器收尾。 - Why: 评审提出的 7 点:顶部占高与装饰过多、记录状态不突出、配置切换看不懂且藏得太深、切视图应换主界面布局、标定与回放面板文字被裁、关窗后命令行不退出、2D 图像无固定宽高比且名字不符。 - Verification: ui_check.py(430 项,新增 top area / instrument panels / clean shutdown 段,含中英×1280/1440 的轨不挤压检查)、test_ui_smoke.py(57 项,新增视图切换、标定不裁切、2D 宽高比、回放按钮文字、传感器选择器等用例)、drive_shared.py(146 项)、locale_studio.py(261 键齐全、zh==en、prefs 对齐)、reproduce.py、ui_snapshot.py 四张复核图。 - Not in this change: 录制文件格式、CSV/MP4 写入路径与记录通道数据流不变;三维面板仍是占位符;回放对话框(含离线深度重算)本身只修了按钮文字。
80 lines
3.9 KiB
Markdown
80 lines
3.9 KiB
Markdown
# 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
|
||
```
|