拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Serial Studio 录制回放视图状态打包(Recording Setup Bundle)全解析:让会话回放“所见即所得“

Serial Studio 录制回放视图状态打包Recording Setup Bundle全解析让会话回放所见即所得【免费下载链接】Serial-StudioOpen-source telemetry dashboard. Supports UART, BLE, MQTT, Modbus, CAN Bus and more.项目地址: https://gitcode.com/GitHub_Trending/se/Serial-Studio录制 Session 数据库回放时Serial Studio 早已能够恢复嵌入式项目 JSON但视图状态光标、缩放/平移、暂停、工作区此前从不随录制携带回放只能打开默认视角。Spec 0062 引入的 Recording Setup Bundle 改变了这一点它为每次录制捆绑一份viewState文档在回放时按用户操作顺序恢复仪表盘让会话回放真正做到你离开时的样子。本文以 spec.md 为主干结合仓库源码DashboardViewState、Export.cpp、Player.cpp逐条拆解需求、数据格式、快照时序与回放恢复流程。背景与动机录制带走了数据却带不走视角Session Database 的录制链路在此之前已经解决了项目级状态的随行问题录制时嵌入项目 JSONsessions.project_json以及实时项目对应的project_metadata.project_json回放时通过Sessions::Player::restoreProjectFromJson恢复见 Player.cpp因此控件布局、工作区、每个控件的widgetSettings插值、面积填充、扫描配置以及 spec 0058 之后的光标标尺/零点都能随录制一同回放。但真正让采样在录制那一刻有意义的视图状态却落在项目文档之外从未随录制传输光标位置Plot 上的 A/B 光标每个图表的缩放/平移可见窗口哪些控件被暂停屏幕上正在显示哪个工作区外部/弹出窗口当时间范围来自 QSettings非 ProjectFile 模式时的绘图时间范围主题以及其他属于会话状态而非项目状态的内容。结果是回放一个会话会打开正确的仪表盘但视角是默认的用户不得不再去找回自己当时正在看的东西。同时Spec 0062 之前对录制之后磁盘上的项目发生了修改没有明确的故事——目前嵌入式副本在回放期间静默胜出回放结束后才通过schedulePreSessionRestore恢复录制前项目但没有任何机制告诉用户两者存在差异。设计目标与非目标Spec 0062 的目标非常聚焦捆绑viewState文档每个控件的光标、可见窗口缩放/平移或世界窗口、暂停标志、用户在图对话框中设置的每图 Y 轴范围覆盖、活动工作区、外部窗口、绘图时间范围与主题 id回放时在项目恢复之后、按应用用户操作相同顺序恢复视图让仪表盘看起来就像当初的样子快照节奏录制开始时、每次防抖后的widgetSettingsChanged、录制结束时各拍一次保证捆绑反映的是最后状态而非最初状态解释分歧当嵌入式项目与当前加载项目不一致时回放提示一次并给出使用录制项目默认或保留我的项目两种选择。明确列入非目标的能力同样值得注意不录制逐帧视图变化为时间线没有回放我的缩放过程不改变项目 JSON 内容也不改动restoreLastProject的工作方式不为 CSV/MDF4 回放打包它们没有逐会话容器来携带视图状态。需求分解R1–R7R1 —view_state作为独立 JSON 文档落库每次会话对应一个 JSON 文档存放在sessions.view_state TEXT列中schema 升级由数据库工作线程在 GUI 线程之外写入数据源是 GUI 侧的一次快照。源码印证DatabaseSchema.cpp 的migrateSessionsTable把view_state加入可空列列表plan.md 记录了kUserVersion从 3 升至 4。写入路径见 Export.cppstoreViewState()通过UPDATE sessions SET view_state ? WHERE session_id ?在工作线程执行遵守仅工作线程写库的会话数据库规则GUI 线程从不直接访问数据库。R2 — 文档内容全部可选缺省即默认viewState的所有字段都是可选的缺失 默认值分为全局层与每控件层全局plotTimeRange、theme、workspace、externalWindows[]每控件按 widget id 键控cursors {ax, ay, bx, by, aVisible, bVisible}、view {xZoom, xPan, yZoom, yPan}或世界窗口、paused、用户设置时的yRange {min, max}。实际实现把两层合并在一个紧凑 JSON 文档中。DashboardViewState::viewStateJson 生成的文档结构为{ version: 1, global: { plotTimeRange: 10.0, theme: dark, workspace: Bench, externalWindows: [] }, widgets: { plot_1: { cursorAX: 0.832, cursorAY: 3.141, cursorBX: 1.024, cursorBY: 2.718, cursorAVisible: true, cursorBVisible: false, showCrosshairs: true, xZoom: 4.0, xPan: 0.25, yZoom: 1.0, yPan: 0.0, paused: false } } }字段键名来自 Plot.qml 的实际写入global与widgets两层结构来自viewStateJson()的root.insert(global, ...)/root.insert(widgets, ...)。关键设计约束视图状态不是项目状态。DashboardViewState的注释明确写着never project state: it never marks the project modified and is dropped whenever the widget identity space changesDashboardViewState.h。这也正是它不并入项目 JSON 的原因——否则每一次缩放都会把项目标记为已修改并在保存.ssproj时落盘详见下文与restoreLastProject的关系。R3 — 快照触发录制开始、防抖变化、录制结束快照触发点共四类录制开始insertSession时写入初始值widgetSettingsChanged本就带防抖光标/缩放变化经 1.5 s 定时器合并与自动保存的防抖一致录制结束finalizeSession时再写一次保证捆绑反映最后状态。实现分两级合并plan.md 的决策QML 侧 500 ms 合并Plot.qml 中的_viewStateTimerinterval: 500, repeat: false把光标拖动、缩放/平移等高频交互聚合成一次saveViewState()推送MultiPlot.qml同样实现MultiPlot.qml。工作线程侧 1.5 s 防抖Export.cpp 定义kViewStateDebounceMs 1500wireViewState()Export.cpp订阅Core::Bus::DashboardViewStaterefreshViewStateSnapshot()刷新快照并重启单发防抖定时器超时后经pushViewStateToWorker()以Qt::QueuedConnection投递到工作线程Export.cpp。saveWidgetViewState/saveGlobalViewState仅在值真实变化时返回trueDashboardViewState.cpp保证防抖看到的是编辑而非重绘。R4 — 回放顺序先项目、再仪表盘、最后视图状态回放必须严格按序恢复项目 JSON已有逻辑→ 重新配置仪表盘 → 在控件真正存在之后widgetCountChanged之后再应用viewState绝不能提前。实现上的巧妙之处在于顺序自然涌现而非显式编排applyBundledViewStatePlayer.cpp通过消息总线发布DashboardViewStateRestoreRequested而 Plot.qml 的restoreViewState()在Component.onCompleted中读取Cpp_UI_Dashboard.widgetViewState(widgetId)——控件在项目恢复后的重建过程中各自读取状态因此先建控件、再应用状态的次序由重建流程本身保证无需额外的显式排序逻辑。R5 — 分歧通知嵌入式项目 vs 磁盘项目回放时把嵌入式project_json与实时项目的序列化结果对比标题 内容哈希不匹配时显示一次非模态通知给出两个选择保留我的通过当前项目回放采样数据集按uniqueId匹配未匹配的忽略。实现落地为仅通知形式见 plan.md 决策表原因API 驱动的回放绝不能阻塞Player.cpp 打开录制前项目路径将磁盘上的实时 JSON 与嵌入 JSON 做对象级比较live.object() embedded.object()不等同则发布一条NotificationRaised严重级kSeverityWarning、频道Sessions文案为Recording uses an older copy of the project并说明关闭会话以返回当前项目。嵌入式项目始终胜出——这与 spec 之前的回放行为一致也意味着回放期间用户看到的是录制时的仪表盘。R6 — 全面降级旧文件与失效控件无view_state的会话完全按今天的方式回放无通知、默认视图viewState引用了已不存在的 widget id 时静默跳过。前者由applyBundledViewState中viewState.isEmpty()分支发布DashboardViewStateClearRequested保证Player.cpp后者由控件读取逻辑天然保证——restoreViewState()对每个字段都做isFinite(...)与存在性检查Plot.qml缺失字段直接忽略。R7 — 离开回放完整还原现场结束回放时恢复录制前的项目与视图与今天的行为完全一致schedulePreSessionRestore捆绑永不泄漏进实时项目。实现分三步capturePreSessionStatePlayer.cpp在进入会话前快照操作模式、项目文件路径与当前视图状态 JSONschedulePreSessionRestore把恢复排队到事件循环避免窗口销毁期间重入平台事件循环Player.cpprestorePreSessionStatePlayer.cpp重开录制前项目、恢复操作模式并发布DashboardViewStateRestoreRequested恢复录制前的视图状态最后清空预会话快照。录制端流水线GUI 快照 → 总线 → 工作线程落库整个录制链路的分工非常清晰GUI 线程UI::Dashboard作为门面持有DashboardViewStateDashboard.cpp暴露saveWidgetViewState/saveGlobalViewState/setViewStateJson/clearViewState仅在真实变化时发出viewStateChangedDashboard.cpp消息总线Sessions::Export订阅DashboardViewState总线消息刷新快照并启动 1.5 s 防抖Export.cpp工作线程ExportWorker::storeViewState()把快照 JSON 写入sessions.view_state时机为会话开始、防抖推送、会话结束Export.cpp。同时DashboardViewState本身也承担布局/面板偏好的持久化工具栏自动隐藏、操作面板、对齐参考线、布局边距/间距QSettings 键Dashboard/AutoHideToolbar等见 DashboardViewState.cpp但这些属于全局偏好而非会话捆绑内容。回放端capture → restore → apply → divergence回放侧Player.cpp的完整顺序链capturePreSessionState()进入会话前快照操作模式、项目路径与录制前的视图状态Player.cpprestoreProjectFromJson()恢复嵌入式项目强制SerialStudio::ProjectFile操作模式Player.cppapplyBundledViewState()发布视图状态恢复请求控件在Component.onCompleted中自行应用同时执行分歧检测与通知Player.cpp退出回放 →schedulePreSessionRestore()→restorePreSessionState()恢复录制前项目、操作模式与视图Player.cpp。值得注意的是PlayerLoaderWorker 负责把view_state读入回放负载tasks.md 的 T4录制端 Export 与其保持同一把互斥锁保护的项目快照旁路。与restoreLastProject的关系restoreLastProject在启动时从 QSettings 重开上次的项目路径并重新应用持久化的操作模式回放早已绕开它——把嵌入式项目换入、关闭时恢复录制前项目。Spec 0062 在嵌入式项目旁边增加第二份更小的文档而不是把视图状态折叠进项目 JSON否则每次缩放都会把项目标记为已修改并随保存落进.ssproj。启动路径没有任何改动spec.md 的 Relation to restoreLastProject 一节。兼容性与验收标准五个验收标准全部勾选AC1图 1 两个光标、图 2 放大 4 倍、图 3 暂停、工作区 Bench 激活——停止后回放四项全部复原AC2录制后编辑项目重命名数据集再回放通知出现一次使用录制项目显示旧名称保留我的显示新名称实现为通知中心警告录制项目始终胜出AC3pre-0062 的会话文件原样回放无通知、默认视图AC4停止回放后实时项目与视图回到回放前的状态AC5无 GUI 线程数据库访问既有规则快照开销不逐帧产生。测试层面tst_sessions_legacy_archive.cpp 必须继续通过可空列与旧读取路径不受影响AC1/AC3/AC4 在运行中的应用中验证见 plan.md 的测试计划。决策记录与已知边界spec 提出的四个开放问题在 plan.md 中敲定开放问题最终决策主题是否入捆绑不记录、不应用回放时恢复主题令人意外记录仅供上下文可能已足够快照节奏500 ms QML 合并 1.5 s 工作线程防抖开始与结束总是写入保留我的选择仅通知无模态框API 驱动的回放绝不能阻塞录制项目始终胜出分歧通知的归属通知中心Sessions频道已知边界tasks.md 的 T6工作区与外部窗口本次未纳入捆绑——需要从组合根Taskbar接一根线到Dashboard已记录为后续工作。此外spec 非目标中的逐帧视图时间线与CSV/MDF4 回放打包均不在范围内。结语Recording Setup Bundle 把视图状态从项目状态中解耦出来形成录制旁边一份独立的、可空、可降级的 JSON 文档GUI 线程持有快照、消息总线搬运、工作线程落库回放时先项目后视图地顺序恢复并用通知中心的一次警告解释嵌入式项目与磁盘项目的分歧。对于依赖 Session Database 复现故障、审计现场或回放历史数据的用户来说这意味着回放的不再只是数据而是当时那个正在观察数据的仪表盘。本文依据 spec.md、plan.md、tasks.md 及仓库源码撰写关键实现可继续阅读 DashboardViewState.cpp、Export.cpp、Player.cpp、DatabaseSchema.cpp 与 Plot.qml。【免费下载链接】Serial-StudioOpen-source telemetry dashboard. Supports UART, BLE, MQTT, Modbus, CAN Bus and more.项目地址: https://gitcode.com/GitHub_Trending/se/Serial-Studio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门