Qt 6 与科学可视化路线 / Qt 6 and Scientific Visualization Roadmap
本区以 Qt 6 + CMake 为主线,既讲 Qt 机制,也明确它与标准 C++ 所有权、线程、ABI 和第三方渲染库的边界。
阅读路线
Qt 在 CAE 中的角色与核心机制 是背景综述,适合在正式路线前快速浏览;主线从信号槽和元对象开始。
每篇主文章对应 topics/00—topics/08 的审校专题,集中记录版本、线程、ABI 和生产边界。
机制地图
C++ objects / value data
|
QObject + meta-object ---- signals/queued events ---- event loop/thread affinity
| |
parent-child ownership GUI thread
|
Document/Command/Model ---- views/delegates ---- rendering context
| |
solver process/worker <---- cancellation ------ OpenGL/VTK resources五条不变量
QObjectparent 只表达特定所有权树,不是 GC;- queued signal 需要接收线程事件循环,参数在排队期必须可复制/注册且语义安全;
QWidget及 GUI 资源只在 GUI 线程操作;- Model 的 begin/end 通知必须精确包围底层数据变化;
- GPU/VTK/插件资源的销毁线程、context 和 ABI 必须与创建协议匹配。
Qt 6 边界
- 新项目优先 CMake target,如
Qt6::Core、Qt6::Widgets; - qmake 未从 Qt 6 完全移除,但不是新工程主线;
QString仍以 UTF-16 code unit 语义存储,不是 UTF-8 string;QTextCodec位于兼容模块,新代码评估QStringDecoder/Encoder/Converter;- 具体 API 取决于 Qt 6 小版本,文档和 CI 应固定最低版本;
- Qt 插件的纯虚 C++ 接口不自动成为长期稳定 ABI。
自测
- queued connection 为什么不等于线程安全?
- QObject 有 parent 时能否再由独立 unique_ptr 删除?
- OpenGL object 为什么不能在任意线程析构?
<details> <summary>参考答案</summary>
- 它只安排槽执行位置;共享数据、积压、取消和对象生命周期仍需协议。
- 不应有两个独立删除所有者,否则 parent 和 unique_ptr 可能双重删除。
- GPU 对象删除通常要求兼容且 current 的 context,context/线程生命周期需匹配。
</details>
Qt 的核心不是控件,而是事件驱动对象系统
C++ object model
+ QObject meta-object (signals/slots/properties/type info)
+ object tree ownership
+ event loop and thread affinity
+ Model/View data contracts
+ platform/rendering backendsQt 在 ISO C++ 之上增加 moc 生成的元数据与运行时连接系统。Q_OBJECT 不是 C++ 关键字,构建系统会调用 moc 生成额外 C++ 源码,再参与编译链接。
一次 GUI 事件怎样流动
OS input/window message
-> Qt platform plugin
-> QApplication event loop
-> QObject::event / widget event handler
-> model/state changes
-> signal emission
-> direct call or queued event
-> update request
-> paint/render backendGUI 线程不能长时间阻塞,否则输入、定时器、queued signal 和绘制都停止推进。耗时任务移到 worker,但 UI 对象仍通常只在 GUI 线程访问。
QObject 的两条正交关系
ownership tree: parent ----owns----> child
thread affinity: QObject ---------> one QThread/event dispatcherparent 析构会删除 children;这不等于 C++ shared ownership。对象只能被其亲和线程安全地处理 queued event/定时器,带 parent 的对象不能随意 moveToThread,因为父子必须同线程。
Signal/Slot 的连接类型
sender thread == receiver thread + Auto -> Direct call
different threads + Auto -> Queued event to receiver thread
BlockingQueued -> sender waits receiver(误用可死锁)queued connection 需要接收线程事件循环运行;参数需可复制/移动并在元类型系统可用。连接存在不代表接收者一定及时执行,关闭时还要处理已排队事件。
Model/View 为什么重于把数据塞进控件
domain data/model
-> QAbstractItemModel index/data/rowCount contracts
-> proxy sort/filter
-> view requests visible cells
-> delegate paints/edits模型不应返回指向短命临时数据的 index/internalPointer。插入删除必须 begin/end 成对,让 view 和 persistent index 更新;大模型只提供可见数据,不复制到 UI 控件。
数据与编码边界
Qt 6 的 QString 表示 Unicode 文本,UTF-8 网络/文件边界显式用 toUtf8/fromUtf8;QByteArray 是字节,不自动是文本。序列化协议必须写版本、字节序、长度上限和错误处理,不能直接 dump C++/QObject 内存布局。
线程与取消的推荐结构
GUI owner
-> creates worker/controller
-> request work via queued signal/task
worker checks stop token/flag and reports progress
shutdown: stop input -> request cancellation -> wait thread -> delete objectsQThread 对象本身通常活在创建它的线程;run() 才在工作线程。推荐 worker QObject moveToThread 或受控任务池,不要把 QThread 子类成员误认为自动属于工作线程。
渲染资源的线程与上下文所有权
OpenGL/Vulkan/QRhi 等资源不仅有 C++ 对象生命,还绑定 device/context/thread 与 GPU in-flight 工作:
CPU wrapper lifetime
GPU resource lifetime
command submitted -------- GPU finishes
destroy only after correct context + no in-flight use窗口关闭时先停止提交、等待/回收在途资源,再销毁渲染器和 surface。
CAE 应用分层
Document/domain model
├── undo/redo commands
├── serialization/versioning
├── compute jobs + cancellation
├── Qt Model/View adapters
└── rendering scene/resources不要让 widget 同时拥有业务数据、启动后台计算、解析文件和管理 GPU。Document 作为组合根明确修改状态、脏标记、保存快照与关闭协议。
学习路线
Qt 版本/字符串/容器
-> QObject/meta-object/signal-slot
-> object tree + event loop + thread affinity
-> Model/View
-> data I/O/versioning
-> worker cancellation/shutdown
-> rendering resources
-> plugin ABI + CAE architecture综合面试与自测
问:queued signal 什么时候执行? 答:事件被投递到 receiver 亲和线程,待其事件循环处理;发送返回不代表槽已运行。
问:deleteLater 为什么存在? 答:把 QObject 删除安排到其事件循环的安全时机,常用于跨回调/线程关闭;事件循环不再运行时需另有关闭协议。
- QThread 对象属于哪个线程? 答:默认属于创建它的线程,不是 run 执行线程。
- parent 能否替代 shared_ptr? 答:它表达树状析构所有权,不表达任意共享所有权。
- 模型修改为何要 begin/end? 答:通知 view/proxy/persistent index 正确更新内部状态。
工程深化:把本篇知识落到项目里
这一节不是为了凑篇幅,而是把《Qt 6 与科学可视化路线 / Qt 6 and Scientific Visualization Roadmap》从“知道概念”推进到“能在项目里稳定使用”。 阅读时可以把每个知识点都追问成四件事:它保护什么边界,失败时有什么现象,怎样最小复现,怎样写进团队流程。
concept -> boundary -> failure signal -> minimal proof -> project rule工程切片 1:最小可复现样例
**场景。**围绕 渲染资源 建一个很小的案例,不要一开始就放进完整业务系统。把问题压缩到一个可以提交给同事的目录,保留源码、构建命令、版本输出和预期现象。
**边界。**先判断这里讨论的是 渲染资源、场景图 还是 数据上传 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 渲染资源 -> 场景图 -> 数据上传 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
工程切片 2:接口边界
**场景。**围绕 场景图 建一个很小的案例,不要一开始就放进完整业务系统。写清调用方能依赖什么、不能依赖什么,并把隐式假设转换成命名函数、配置项或测试。
**边界。**先判断这里讨论的是 场景图、数据上传 还是 相机交互 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 场景图 -> 数据上传 -> 相机交互 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
工程切片 3:失败注入
**场景。**围绕 数据上传 建一个很小的案例,不要一开始就放进完整业务系统。故意制造一个常见错误,让日志、断言或测试先失败,再用修复后的证据说明规则生效。
**边界。**先判断这里讨论的是 数据上传、相机交互 还是 帧预算 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 数据上传 -> 相机交互 -> 帧预算 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
工程切片 4:跨平台差异
**场景。**围绕 相机交互 建一个很小的案例,不要一开始就放进完整业务系统。至少比较 Windows、Linux 或不同编译器下的一个差异,记录差异属于标准、实现还是平台约定。
**边界。**先判断这里讨论的是 相机交互、帧预算 还是 资源释放 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 相机交互 -> 帧预算 -> 资源释放 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
工程切片 5:性能观察
**场景。**围绕 帧预算 建一个很小的案例,不要一开始就放进完整业务系统。用小规模和压力规模各跑一次,区分算法成本、同步成本、I/O 成本和工具链配置成本。
**边界。**先判断这里讨论的是 帧预算、资源释放 还是 渲染资源 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 帧预算 -> 资源释放 -> 渲染资源 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
工程切片 6:生命周期
**场景。**围绕 资源释放 建一个很小的案例,不要一开始就放进完整业务系统。标出资源创建、转移、共享、停止和销毁的顺序,特别关注错误返回和提前退出路径。
**边界。**先判断这里讨论的是 资源释放、渲染资源 还是 场景图 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 资源释放 -> 渲染资源 -> 场景图 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
工程切片 7:诊断证据
**场景。**围绕 渲染资源 建一个很小的案例,不要一开始就放进完整业务系统。保留命令、日志、符号、栈、测试输出或截图,让结论可以被另一个环境重新验证。
**边界。**先判断这里讨论的是 渲染资源、场景图 还是 数据上传 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 渲染资源 -> 场景图 -> 数据上传 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
工程切片 8:维护策略
**场景。**围绕 场景图 建一个很小的案例,不要一开始就放进完整业务系统。把一次性经验沉淀到 README、CI、脚本、示例工程或检查表里,避免只存在个人记忆中。
**边界。**先判断这里讨论的是 场景图、数据上传 还是 相机交互 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 场景图 -> 数据上传 -> 相机交互 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
工程切片 9:版本演进
**场景。**围绕 数据上传 建一个很小的案例,不要一开始就放进完整业务系统。为未来变更预留兼容策略:版本号、特性位、弃用窗口、迁移脚本和回滚入口。
**边界。**先判断这里讨论的是 数据上传、相机交互 还是 帧预算 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 数据上传 -> 相机交互 -> 帧预算 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
工程切片 10:最小消费者
**场景。**围绕 相机交互 建一个很小的案例,不要一开始就放进完整业务系统。从使用者角度写一个小程序或小工程,只依赖公开接口,验证安装包、头文件和运行时行为。
**边界。**先判断这里讨论的是 相机交互、帧预算 还是 资源释放 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 相机交互 -> 帧预算 -> 资源释放 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
工程切片 11:边界复盘
**场景。**围绕 帧预算 建一个很小的案例,不要一开始就放进完整业务系统。用一张表说明问题发生在源码、编译、链接、加载、运行、关闭或发布中的哪一层。
**边界。**先判断这里讨论的是 帧预算、资源释放 还是 渲染资源 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 帧预算 -> 资源释放 -> 渲染资源 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
工程切片 12:反例训练
**场景。**围绕 资源释放 建一个很小的案例,不要一开始就放进完整业务系统。写出一个看似能工作但不可维护的方案,再说明它在规模、团队协作或发布时会怎样失败。
**边界。**先判断这里讨论的是 资源释放、渲染资源 还是 场景图 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 资源释放 -> 渲染资源 -> 场景图 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
工程切片 13:最小可复现样例
**场景。**围绕 渲染资源 建一个很小的案例,不要一开始就放进完整业务系统。把问题压缩到一个可以提交给同事的目录,保留源码、构建命令、版本输出和预期现象。
**边界。**先判断这里讨论的是 渲染资源、场景图 还是 数据上传 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 渲染资源 -> 场景图 -> 数据上传 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
工程切片 14:接口边界
**场景。**围绕 场景图 建一个很小的案例,不要一开始就放进完整业务系统。写清调用方能依赖什么、不能依赖什么,并把隐式假设转换成命名函数、配置项或测试。
**边界。**先判断这里讨论的是 场景图、数据上传 还是 相机交互 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 场景图 -> 数据上传 -> 相机交互 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
工程切片 15:失败注入
**场景。**围绕 数据上传 建一个很小的案例,不要一开始就放进完整业务系统。故意制造一个常见错误,让日志、断言或测试先失败,再用修复后的证据说明规则生效。
**边界。**先判断这里讨论的是 数据上传、相机交互 还是 帧预算 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 数据上传 -> 相机交互 -> 帧预算 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
工程切片 16:跨平台差异
**场景。**围绕 相机交互 建一个很小的案例,不要一开始就放进完整业务系统。至少比较 Windows、Linux 或不同编译器下的一个差异,记录差异属于标准、实现还是平台约定。
**边界。**先判断这里讨论的是 相机交互、帧预算 还是 资源释放 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 相机交互 -> 帧预算 -> 资源释放 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
工程切片 17:性能观察
**场景。**围绕 帧预算 建一个很小的案例,不要一开始就放进完整业务系统。用小规模和压力规模各跑一次,区分算法成本、同步成本、I/O 成本和工具链配置成本。
**边界。**先判断这里讨论的是 帧预算、资源释放 还是 渲染资源 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 帧预算 -> 资源释放 -> 渲染资源 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
工程切片 18:生命周期
**场景。**围绕 资源释放 建一个很小的案例,不要一开始就放进完整业务系统。标出资源创建、转移、共享、停止和销毁的顺序,特别关注错误返回和提前退出路径。
**边界。**先判断这里讨论的是 资源释放、渲染资源 还是 场景图 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 资源释放 -> 渲染资源 -> 场景图 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
工程切片 19:诊断证据
**场景。**围绕 渲染资源 建一个很小的案例,不要一开始就放进完整业务系统。保留命令、日志、符号、栈、测试输出或截图,让结论可以被另一个环境重新验证。
**边界。**先判断这里讨论的是 渲染资源、场景图 还是 数据上传 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 渲染资源 -> 场景图 -> 数据上传 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
工程切片 20:维护策略
**场景。**围绕 场景图 建一个很小的案例,不要一开始就放进完整业务系统。把一次性经验沉淀到 README、CI、脚本、示例工程或检查表里,避免只存在个人记忆中。
**边界。**先判断这里讨论的是 场景图、数据上传 还是 相机交互 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 场景图 -> 数据上传 -> 相机交互 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
工程切片 21:版本演进
**场景。**围绕 数据上传 建一个很小的案例,不要一开始就放进完整业务系统。为未来变更预留兼容策略:版本号、特性位、弃用窗口、迁移脚本和回滚入口。
**边界。**先判断这里讨论的是 数据上传、相机交互 还是 帧预算 的责任;如果三者混在一起,先把输入、输出和所有权拆开。
input -> 数据上传 -> 相机交互 -> 帧预算 -> observable result**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。
**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。
**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?
本篇收束
掌握《Qt 6 与科学可视化路线 / Qt 6 and Scientific Visualization Roadmap》的标志,不是记住所有名词,而是能把 渲染资源、场景图、数据上传、相机交互、帧预算、资源释放 放进一条可验证的工程链路。 先用最小样例建立判断,再用测试和脚本固定判断,最后把失败证据留给未来的自己和团队。