上一篇写 OpenCascade 基础环境准备的时候,很多朋友在后台问我:到底怎么把 OCC 的渲染窗口塞进 Qt 界面里?每次都要翻官方示例太痛苦。我最近做一个自研桌面工具的三维显示模块,正好把整套流程完整走了一遍。从 Qt 工程里引入 occ 库、搭 CMake 模板、加载模型到最终发布 Demo,踩过的坑和最终跑通的方案都在这篇笔记里。这篇面向的是正准备做 Qt+OpenCascade 集成、但又不想被官方示例绕晕的开发者,已经有 C++ 基础和最基本的 Qt 使用经验就行。
1. 项目概述与整体思路
1.1 这个 Demo 解决的问题是什么
做 CAD 相关的桌面工具,最头疼的一件事就是三维显示部分。OpenCascade 本身有完整的可视化模块,但它的原生示例窗口长得很“朴素”,离真正能塞进产品里的效果差太远。Qt 的好处就是界面生态成熟,按钮、树形控件、属性面板、停靠窗口全部现成,而且信号槽机制天然适合做交互逻辑。
这两者一结合,就形成了我现在这套惯用方案:Qt 负责外壳和交互框架,OpenCascade 负责几何内核和渲染显示。具体到这篇笔记要实现的 Demo,就是在一个 Qt 窗口中嵌入 OCC 的三维视图,支持鼠标旋转、缩放、平移,能加载一个 STEP 模型并显示出来。做完这个模板之后,后面再做模型浏览器、轻量化查看器或者参数化建模工具,都有了一个可以直接复用的底子。
1.2 方案选型:为什么这么搭
先说编译器。OCC 官方提供的预编译包基本都是用 MSVC 编译的,所以 Qt 这边也要对应选择 MSVC 版本。很多新手拿默认安装的 MinGW 版 Qt 去链接 OCC 预编译库,结果一堆 LNK 错误,这并不是你代码写错了,是两边的 ABI 不兼容。MinGW 和 MSVC 在 C++ 的符号修饰、标准库实现上差别都很大,强行混用纯属浪费时间。我在表格里整理了常见的差别:
| 对比项 | MSVC + Qt | MinGW + Qt |
|---|---|---|
| OCC 预编译库兼容性 | 匹配,可直接链接 | 不匹配,需要自己用 MinGW 编译 OCC |
| 调试器体验 | Visual Studio 生态,调试图、内存检查方便 | 相对弱一些 |
| 发布部署 | 主要依赖 windeployqt 和 VC 运行库 | 理论上可免 VC 运行库,但 OCC 预编译包还是 MSVC 系 |
| 第三方库兼容性 | 工业级库基本都提供 MSVC 包 | 能找到的少,常要自己编 |
再说构建工具。qmake 虽然用起来简单,但一旦工程里模块多起来,条件编译和第三方依赖管理就会变得别扭。OpenCascade 官方支持 CMake,Qt 新版本官方也在推 CMake,所以我这篇笔记的模板直接用 CMake,后面加模块、加第三方库都方便。
库的版本选择上,我用的是 OpenCascade 7.x 系列,Qt 端如果是从老项目迁移过来的建议用 5.15 LTS,如果是新项目直接上 Qt 6 问题也不大。OCC 的 AIS 接口在 7.x 版本里有不少调整,但核心用法和 6.x 差别还不算大,网上能搜到的大量老示例仍然可以借鉴,只要注意类名和头文件路径的小差异就可以了。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. OCC 库与 Qt 环境的搭配细节
2.1 版本对应关系与 ABI 一致性
OpenCascade 对编译器版本非常敏感。同一个 OCC 预编译包,可能对应的是某一年份的 MSVC 工具集版本,如果你的 Qt 是用另一个工具集编译的,比如 VS2019 和 VS2022,链接阶段就会出现 LNK2038 这类版本不匹配错误。我不建议在这种问题上和编译器做斗争,最省事的方法是:OCC 用什么编译环境,Qt 就尽量用对应的 MSVC 工具集。
具体到 Qt Creator 里,安装 Qt 时要把 MSVC 那一套勾上,编译器选择时注意是 x64 版本。现在的 OCC 预编译包基本都是 64 位,所以 Qt 套件也必须选 64 位,这块错了后面全部白搭。我的习惯是在工程说明文档里固定版本组合,比如“OCCT 7.7.0 + Qt 5.15.2 + MSVC2019 64bit”,之后所有机器都照这个环境来,避免团队内部出现神仙配置。
2.2 OCC 依赖的组件清单
OpenCascade 是一个组件化很明显的库,链接的时候并不是一个巨大的 lib,而是按功能拆分的 TK 系列模块。一个最简单的三维显示 Demo,通常需要这些:
| 模块 | 作用 |
|---|---|
| TKernel | 基础工具类、容器、异常处理,OCC 的地基 |
| TKMath | 几何计算相关,向量、矩阵、曲线曲面数学 |
| TKBRep | B-Rep 拓扑数据结构,Shape 的核心 |
| TKTopAlgo | 拓扑算法,比如 STEP 读取后的形状处理会用到 |
| TKPrim | 基础体素,做 demo 时可加可不加 |
| TKService | 图形抽象层,窗口、上下文的基础 |
| TKV3d | 三维视图核心,Viewer、View 都在这 |
| TKOpenGl | OpenGL 渲染驱动 |
| TKAIS | 交互选择框架,AIS_Shape 这类对象 |
| TKSTEP | STEP 格式读写,加载模型必备 |
手动去记这些依赖会非常痛苦,而且版本不同模块列表也会有细微差别。所以第 3 节里我直接用 CMake 的 find_package 机制来处理,它会自动把目标模块和依赖解析好,人只需要维护一个近似手写的最小组件列表就可以。
这里也提醒一个常见认知误区:不要把发布目录里所有 TK 开头的 DLL 一股脑塞进安装包。虽然能用,但体积暴涨。正确做法是只带需要的模块,等工程结构稳定之后再手工精简。Demo 阶段可以大方一点全带,但心里要有数哪些其实用不上。
2.3 Headers 路径与 Debug/Release 的坑
OCC 的头文件路径一般长这样:opencascade-7.7.0\inc,里面几百个 hxx 文件。库文件则在 win64\vc14\libd(Debug)或 win64\vc14\lib(Release)。注意,OCC 预编译包对 Debug 阶段的支持通常不完整,很多模块只有 Release 库。如果你的工程配置必须是 Debug 链接 Release 的 OCC 库,不是不能跑,但会有一些微妙的问题,比如容器对象在切换运行时行为异常、内存检查器报错之类。
我的经验是:Demo 千万别开 Debug 模式咬这口硬骨头,直接用 Release 配置编译,省下的时间足够多做两个功能。如果后面真要做正式开发,那就自己从源码编译一份完整的带 Debug 符号的 OCC 库。这一步绕不开,但那是规划产品路线时才需要考虑的事。
3. 搭建工程模板:目录结构与 CMake 配置
3.1 可复用的目录结构
搭工程模板的核心目的是减少重复劳动。我把一个固定形态的目录摆放出来,后面每个新项目就在这个框架上长出来。推荐结构如下:
code复制OccQtTemplate/
├─ CMakeLists.txt
├─ src/
│ ├─ main.cpp
│ ├─ MainWindow.h
│ ├─ MainWindow.cpp
│ ├─ OccViewWidget.h
│ └─ OccViewWidget.cpp
├─ third_party/
│ ├─ opencascade/
│ │ ├─ inc/
│ │ └─ win64/
│ └─ qt/ # Qt 一般由 CMake 查找,不强制放这里
├─ resources/
│ ├─ models/ # 示例 STEP/IGES 文件
│ └─ fonts/
└─ scripts/
└─ deploy.bat
把 OCC 放在工程树内的 third_party 而不是全局安装,优点很明显:工程拷贝到别的机器不需要重新配置环境变量,团队协作时每个人的路径一致,构建脚本好写。代价是库体积会进入版本库,但如果只是在内部使用,这点空间完全值得。
3.2 CMake 核心配置逐个解释
CMakeLists.txt 是整套模板的心脏。我先把一个能用的版本放出来,然后一行一行说为什么要这么写。
cmake复制cmake_minimum_required(VERSION 3.16)
project(OccQtTemplate LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUI ON)
find_package(Qt5 COMPONENTS Widgets REQUIRED)
set(OpenCASCADE_DIR "${CMAKE_SOURCE_DIR}/third_party/opencascade/lib/cmake/opencascade")
find_package(OpenCASCADE REQUIRED)
set(OCC_COMPONENTS
TKernel
TKMath
TKBRep
TKTopAlgo
TKV3d
TKOpenGl
TKService
TKAIS
TKSTEP
TKPrim
)
add_executable(OccQtTemplate
src/main.cpp
src/MainWindow.cpp
src/MainWindow.h
src/OccViewWidget.cpp
src/OccViewWidget.h
)
target_include_directories(OccQtTemplate PRIVATE src)
target_link_libraries(OccQtTemplate
PRIVATE
Qt5::Widgets
${OpenCASCADE_LIBRARIES}
)
if(WIN32)
set_target_properties(OccQtTemplate PROPERTIES WIN32_EXECUTABLE ON)
endif()
最关键的两行:find_package(OpenCASCADE REQUIRED) 负责让 CMake 找到 OCC 的版本配置。OpenCASCADE_DIR 指定到 lib/cmake/opencascade 目录,是因为 OCC 的 CMake 配置文件就在这个位置,如果安装在系统路径,这一行可以省略,但模板里我强制指定为工程相对路径,这样所有依赖都在工程内部,换机器不会炸。
${OpenCASCADE_LIBRARIES} 是 OCC 的 CMake 包自动生成的目标列表。这里有一个细节:直接没有在 target_link_libraries 里写绝对路径的 .lib 文件,而是让 find_package 去解析依赖关系。这样能避免遗漏某些隐藏依赖。
编译阶段还要注意:OCC 的某些特性开关会影响编译。比如如果打开了 VTK 集成或者 TBB 支持,需要在 CMake 里额外添加 find_package(TBB)。基本 Demo 不用管,但后面做大规模网格剖分、并行计算时就得考虑 TBB 了。
3.3 主程序的最小骨架
main.cpp 不需要复杂到哪去,就是一个最普通的 Qt 启动流程:
cpp复制#include <QApplication>
#include "MainWindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow w;
w.show();
return app.exec();
}
MainWindow 里放一个中心 widget,这个 widget 就是后面要写的 OccViewWidget。这个阶段的目的只有一个:确认工程能编译通过,窗口能弹出来。如果在这个环节出现了链接错误,大概率是编译器不匹配或库路径没找对,请不要往下继续,先把环境调通。
4. 将 OCC 视图嵌入 Qt 窗口
4.1 OCC 窗口绑定到底在干什么
OCC 的三维渲染本质上是通过 OpenGL 绘制到一个原生窗口句柄上的。它并不直接认识 QWidget,它只认平台相关的窗口句柄,在 Windows 上就是 HWND。所以集成 Qt 的关键一步,就是把 QWidget 的句柄取出来交给 OCC 的 Aspect_NeutralWindow。这个类可以理解成 OCC 给外部窗口准备的“适配器”,它不关心上层是谁创建的窗口,只要有一个原生句柄就能住进去。
这里有个非常重要的点:winId() 调用时机。QWidget 在还没有显示的时候,winId() 会强制创建一次原生窗口,但有些平台下属性还没完全就绪。我的习惯是先在构造函数里调用一次 setAttribute(Qt::WA_NativeWindow) 强制原生窗口成立,同时 setAttribute(Qt::WA_PaintOnScreen) 告诉 Qt 不要管这个区域的绘制,因为渲染工作全部由 OCC 通过 OpenGL 完成。这两行是很多白屏问题的根源,去掉它们以后除非你手动处理重绘,否则经常出现乱七八糟的闪烁和残影。
窗口尺寸绑定也要注意。OCC 的 View 有一个内部尺寸,Qt 端 resizeEvent 里必须调用 view->MustBeResized() 通知 OCC 视图区域变了,否则 Resize 后图形会被拉伸或扭曲。这个问题几乎每次新建项目都会遇到,我几乎条件反射地在所有 QWidget 子类里加上 resizeEvent 的透传。
4.2 OccViewWidget 的实现要点
直接上代码,这是一个最小可用的 OCC 显示控件:
cpp复制// OccViewWidget.h
#pragma once
#include <QWidget>
#include <OpenGl_GraphicDriver.hxx>
#include <V3d_Viewer.hxx>
#include <V3d_View.hxx>
#include <AIS_InteractiveContext.hxx>
class OccViewWidget : public QWidget
{
Q_OBJECT
public:
explicit OccViewWidget(QWidget *parent = nullptr);
protected:
void resizeEvent(QResizeEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void wheelEvent(QWheelEvent *event) override;
private:
Handle(V3d_Viewer) m_viewer;
Handle(V3d_View) m_view;
Handle(AIS_InteractiveContext) m_context;
QPoint m_lastPoint;
};
cpp复制// OccViewWidget.cpp
#include "OccViewWidget.h"
#include <Aspect_NeutralWindow.hxx>
#include <Graphic3d_GraphicDriver.hxx>
OccViewWidget::OccViewWidget(QWidget *parent)
: QWidget(parent)
{
setAttribute(Qt::WA_NativeWindow);
setAttribute(Qt::WA_PaintOnScreen);
setMinimumSize(640, 480);
setFocusPolicy(Qt::StrongFocus);
Handle(Aspect_DisplayConnection) displayConnection = new Aspect_DisplayConnection();
Handle(OpenGl_GraphicDriver) driver = new OpenGl_GraphicDriver(displayConnection);
m_viewer = new V3d_Viewer(driver);
m_viewer->SetDefaultLights();
m_viewer->SetLightOn();
m_view = m_viewer->CreateView();
Handle(Aspect_NeutralWindow) window = new Aspect_NeutralWindow();
window->SetNativeHandle(reinterpret_cast<Aspect_Drawable>(winId()));
window->SetSize(width(), height());
m_view->SetWindow(window);
if (!m_view->IsDefined())
m_view->SetWindow(window);
m_context = new AIS_InteractiveContext(m_viewer);
m_view->MustBeResized();
}
这个构造函数里有一个我在正式项目里也保留的“双保险”写法:先 SetWindow 一次,再用 IsDefined() 判断是否成功。不同版本的 OCC 对 Aspect_NeutralWindow 的初始化要求不太一样,有的版本需要先 SetSize 再 SetNativeHandle,有的版本反过来。双保险虽然看起来不够优雅,但配合 IsDefined() 的判断,确实能兼容一部分 API 差异。
4.3 鼠标交互:旋转、平移、缩放
没有鼠标交互的三维窗口跟静态截图没区别。OCC 的 V3d_View 提供了现成的旋转、平移、缩放方法,我们要做的就是把 Qt 的鼠标事件转译成对应的调用。
cpp复制void OccViewWidget::mousePressEvent(QMouseEvent *event)
{
m_lastPoint = event->pos();
}
void OccViewWidget::mouseMoveEvent(QMouseEvent *event)
{
if (m_view.IsNull())
return;
QPoint cur = event->pos();
if (event->buttons() & Qt::MiddleButton)
{
if (event->modifiers() & Qt::ControlModifier)
{
m_view->Pan(m_lastPoint.x(), m_lastPoint.y(), cur.x(), cur.y());
}
else
{
m_view->Rotate(m_lastPoint.x(), m_lastPoint.y(), cur.x(), cur.y());
}
}
m_lastPoint = cur;
}
void OccViewWidget::wheelEvent(QWheelEvent *event)
{
if (m_view.IsNull())
return;
double factor = event->angleDelta().y() > 0 ? 1.1 : 1.0 / 1.1;
m_view->SetScale(m_view->Scale() * factor);
}
交互手感上有一个心得:旋转和缩放的灵敏度不是越高越好,数值太大看着很“飘”,太小又觉得“钝”。我调过几版以后,缩放系数固定用 1.1 倍,旋转则直接依赖 OCC 内部的坐标系换算,大多数情况下丝滑度已经够用。如果想做精细的拾取、框选,后续在 mousePressEvent 里通过 AIS_InteractiveContext 的 MoveTo 和 Select 系列方法扩展即可,这个模板已经留好了接口位置。
4.4 加载一个 STEP 模型并显示
三维窗口空跑不是目的,加载真实模型才是演示的关键。OCC 里读取 STEP 非常直接:
cpp复制#include <BRep_Builder.hxx>
#include <BRepTools.hxx>
#include <AIS_Shape.hxx>
void loadStep(const QString &filename)
{
TopoDS_Shape shape;
BRep_Builder builder;
Standard_Boolean ok = BRepTools::Read(shape, filename.toLocal8Bit().constData(), builder);
if (!ok)
return;
Handle(AIS_Shape) aisShape = new AIS_Shape(shape);
m_context->Display(aisShape, Standard_True);
m_view->FitAll();
}
两步就完成了一个工业级几何内核的“显示模型”诉求。这里值得多说一句 FitAll() 的作用:它能让视图自动调整到刚好包容整个模型的位置和缩放比例。如果不做这一步,模型可能出现在视野之外,或者小到看不见,新手经常误以为“模型没加载成功”,实际上只是视角不对。
5. Demo 构建与发布打包
5.1 Release 构建和依赖自检
工程模板写完了,接下来要把 Demo 变成一个能发给别人使用的 exe。这里有一套我每次都会执行的固定动作。先用 CMake 生成 Release 配置的工程,编译通过后在构建目录找到 OccQtTemplate.exe。不要急着复制走,第一步是在开发机上检查它的动态库依赖。
最简单的方式是用 Visual Studio 自带的 dumpbin:
bash复制dumpbin /dependents OccQtTemplate.exe
输出里会列出所有 import 的 DLL 名称,包括 Qt5Widgets.dll、TK*.dll、FreeType6.dll 等。对照这份清单,就能知道发布目录里最核心需要准备哪些文件。不过 dumpbin 只能看一层依赖,如果一个 DLL 自身又依赖另一个 DLL,那就得继续递归检查,比较麻烦。我通常用命令行工具快速扫一遍,定位到主要缺失项,再手工去安装目录里把对应文件补进发布目录。
5.2 用 windeployqt 收集 Qt 运行库
Qt 运行库的收集不需要手动,官方提供了 windeployqt 工具。
bash复制windeployqt --release --no-translations --no-compiler-runtime Release\OccQtTemplate.exe
这条命令会把 Qt 的 DLL、platforms 插件、styles 插件等全部复制到 exe 所在目录。注意,--no-compiler-runtime 参数我特意留着,是因为 MSVC 运行库我更倾向于在目标机器上直接安装官方 Redistributable,而不是把一堆 vcruntime140.dll 塞进目录。如果目标机器没有管理员权限安装,那再把编译器运行库复制到本地目录也不晚。
Qt 的 platform 插件是个隐蔽的坑。很多人把 exe 和相关 DLL 拷贝过去,双击一点反应没有,用命令行运行才看到 “could not find or load the Qt platform plugin windows”。这不是缺 Qt 核心库,而是缺 platforms\qwindows.dll。windeployqt 会自动生成这个目录结构,所以强烈建议用工具而不是手动复制。
5.3 OCC 的 DLL 和资源文件收集
OCC 这边的 DLL 位置在 third_party\opencascade\win64\vc14\bin,里面以 TK 开头的一大堆。第一次做演示可以直接把整个 bin 目录拷过去,图个省心,等以后要正式交付再按依赖精简。
但 OCC 还有一个容易被忽略的部分:资源文件。OpenCascade 渲染着色程序和字体不是编译进 DLL 的,运行时会根据环境变量寻找。常见变量是 CSF_ShaderRoot 和 CSF_FontPaths。如果在开发机上跑得好好的,换一台机器就报告场景初始化失败或者图形显示异常,十有八九就是这两个环境变量没设置。
为了让 Demo 在任意机器上都能跑,我会在 main.cpp 中用 qputenv 在 QApplication 初始化之前设置好路径,指向 exe 同级的 resources 目录:
cpp复制qputenv("CSF_ShaderRoot", "resources/Shaders");
qputenv("CSF_FontPaths", "resources/Fonts");
这样做比依赖系统环境变量更稳。发布目录在目标机上即使被拷贝到别的位置,只要目录内部相对结构不变,就还能正常工作。
发布打包的最终目录形式大致是这样:
code复制dist/
├─ OccQtTemplate.exe
├─ Qt5Widgets.dll
├─ Qt5Gui.dll
├─ Qt5Core.dll
├─ TKernel.dll
├─ TKMath.dll
├─ TKBRep.dll
├─ TKV3d.dll
├─ TKOpenGl.dll
├─ TKService.dll
├─ TKAIS.dll
├─ FreeType6.dll
├─ platforms/
│ └─ qwindows.dll
├─ styles/
└─ resources/
├─ Shaders/
└─ Fonts/
6. 常见问题与排查思路
6.1 编译链接阶段的高频错误
这个阶段的问题通常能通过搜索引擎解决,但原因无非集中在几类。我把它整理成一张速查表,照着排查会非常快:
| 错误现象 | 常见原因 | 处理方式 |
|---|---|---|
| LNK2038 版本不匹配 | Qt/MSVC 工具集与 OCC 编译环境不一致 | 统一使用同版本 MSVC 编译的 Qt,且与 OCC 预编译包匹配 |
| 找不到 TKernel.lib 等文件 | OpenCASCADE_DIR 指向错误或库路径未配置 | 检查 find_package 前是否正确设置 OpenCASCADE_DIR |
| 大量 LNK2019 未解析的外部符号 | 缺少某个 OCC 模块 | 在 OCC_COMPONENTS 中补充模块,重新生成工程 |
| x86/x64 冲突 | 用了 32 位 Qt 配 64 位 OCC | 全部换成 64 位 |
| 无法打开包含文件 xxx.hxx | include 路径没写 | 确认 OCC 的 inc 目录被包含 |
6.2 运行期白屏与闪退
窗口能弹出来,但里面是白茫茫一片,这是集成初期最容易见到的现象。第一优先级检查是不是没有设置 Qt::WA_PaintOnScreen。这个属性一旦缺失,Qt 会接管窗口背景的重绘,把 OCC 绘制的内容盖掉,表现就是要么白屏要么花屏。
还有一类闪退,发生在初始化 m_viewer 之前就调用了 m_view。OCC 的对象体系有严格的创建顺序:GraphicDriver 必须先于 Viewer,Viewer 必须先于 View,View 必须先于 Context。任何一个环节跳过或者颠倒,轻则空指针异常,重则直接崩溃。如果程序在构造函数里就崩掉,按这个顺序把日志打出来,基本能定位到哪一步出了问题。
还有机率出现“窗口显示出来,但模型一旋转就撕裂”的情况。这通常和垂直同步有关,可以在创建 Viewer 后尝试开启 vblsync 或者设置交换间隔。有些显卡驱动默认关闭垂直同步,快速旋转时视觉上会有明显撕裂,但不是致命错误,一般不影响逻辑功能。
6.3 发布到目标机后的经典问题
开发机上跑得好好的,一拷贝到没有装 Qt 的机器就双击没反应。这个问题的源头九成是 DLL 缺失。建议先打开系统日志或者用命令行从控制台运行 exe,它会直接提示缺哪个 DLL。确定缺少的对象以后,再用一整套依赖分析工具检查完整依赖树。
OCC 本身的 DLL 之间也存在依赖关系,比如 TKOpenGl 会依赖 FreeType6.dll,如果只拷贝了 TK 开头的文件而漏掉 FreeType,启动时依然会报错。这类间接依赖最容易漏。
目标机上如果出现“着色器编译失败”或“字体路径不存在”的错误,那就是我前面提的 CSF_ShaderRoot 和 CSF_FontPaths 没有正确指向资源目录。这里的坑在于,开发机上 OCC 安装到系统目录时,环境变量可能已经由安装程序写好了,于是开发环境一切正常;而目标机上没有安装 OCC,环境变量自然不存在。用程序内 qputenv 相对路径的方式,能有效规避。
6.4 一个值得早知道的部署技巧
最后多分享一个我在项目里踩出来的经验:不要等发布阶段才做依赖检查,而是在第一次编译通过后,立刻手动把构建目录里的 exe 复制到一个干净目录,用 windeployqt 走一遍完整发布流程。哪怕只是内部自测,也强制在干净环境中运行一次。这样做可以把环境依赖问题提前暴露,而不是等到要交付的时候才着急处理。
另外,发布目录里建议保留一份依赖清单文本,记录每个 DLL 来自哪个安装包或哪个编译目录。虽然听起来繁琐,但当你的第三方库越来越多,这份清单能在半年后帮你快速定位“这个 DLL 怎么升级、那个文件能不能删除”这类问题,省去大量回忆时间。
在我实际用下来,这套 Qt+OpenCascade 工程模板最大的价值不是第一个 Demo 跑通的那一瞬间,而是后面每个新功能都有了一个稳固的起点。现在我可以短期之内搭出新的显示工具,只需要把加载模型、交互操作、界面布局按需求组合就行,不必再纠结底层链接和初始化顺序。下一篇会继续写拾取和高亮、自定义交互这些更接近产品形态的内容。
