10.VTK+Qt 集成
VTK+Qt集成学习(第九阶段)
背景:之前写的全部是控制台独立vtk程序;工业软件不会这么用,三维视图必须嵌入Qt窗口。 核心组件:QVTKRenderWindowInteractor,VTK官方提供的Qt封装控件,把vtkRenderWindow嵌入Qt Widget。
⚠️版本提醒:VTK9.7,Qt5.15 / Qt6都支持;QVTKRenderWindowInteractor不再是单独的头文件,属于模块
VTK::GUISupportQt,CMake必须开启这个模块。
一、编译VTK时必须打开的CMake选项
编译VTK源码,CMake-GUI勾选:
VTK_MODULE_ENABLE_VTK_GUISupportQt → ON
VTK_QT_VERSION → 自动检测,选5或者6,和你本机Qt版本对齐
如果不开启
GUISupportQt,就找不到QVTKRenderWindowInteractor,编译报错。
编译安装完成之后,你的工程CMake才可以找到这个组件。
二、Qt项目CMakeLists模板
cmake_minimum_required(VERSION 3.20)
project(VtkQtDemo)
set(CMAKE_CXX_STANDARD 17)
# Qt
find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
# VTK,必须引入GUISupportQt
find_package(VTK REQUIRED COMPONENTS
CommonCore
RenderingCore
RenderingOpenGL2
InteractionStyle
GUISupportQt # 关键,Qt绑定模块
)
qt5_wrap_cpp(MOC_SOURCES mainwindow.h)
add_executable(VtkQtDemo
main.cpp
mainwindow.h
mainwindow.cpp
${MOC_SOURCES}
)
target_link_libraries(VtkQtDemo
Qt5::Core Qt5::Gui Qt5::Widgets
${VTK_LIBRARIES}
)
# vtk初始化宏,必须写
vtk_module_autoinit(
TARGETS VtkQtDemo
MODULES ${VTK_LIBRARIES}
)
三、代码示例:把VTK三维窗口嵌入Qt窗口
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QVTKRenderWindowInteractor.h>
#include <vtkSmartPointer.h>
#include <vtkRenderer.h>
#include <vtkCylinderSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
private:
// Qt控件,承载VTK渲染窗口
QVTKRenderWindowInteractor* m_vtkWidget{nullptr};
vtkSmartPointer<vtkRenderer> m_renderer;
vtkSmartPointer<vtkActor> m_actor;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QVBoxLayout>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
this->resize(800,600);
// 1. 创建Qt-VTK混合控件
m_vtkWidget = new QVTKRenderWindowInteractor(this);
// 2. 渲染器
m_renderer = vtkSmartPointer<vtkRenderer>::New();
m_renderer->SetBackground(0.2,0.2,0.2);
// 将渲染器绑定到控件的渲染窗口
m_vtkWidget->GetRenderWindow()->AddRenderer(m_renderer);
// 造一个测试几何体
auto cylinder = vtkSmartPointer<vtkCylinderSource>::New();
cylinder->SetHeight(10);
cylinder->SetRadius(3);
cylinder->Update();
auto mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData(cylinder->GetOutput());
m_actor = vtkSmartPointer<vtkActor>::New();
m_actor->SetMapper(mapper);
m_renderer->AddActor(m_actor);
m_renderer->ResetCamera();
// 布局:把vtkWidget放到主窗口
QWidget* central = new QWidget(this);
QVBoxLayout* lay = new QVBoxLayout(central);
lay->addWidget(m_vtkWidget);
this->setCentralWidget(central);
// ⭐重要:启动交互器
m_vtkWidget->GetInteractor()->Initialize();
}
main.cpp
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
运行效果:Qt窗口里面出现三维视图,可以鼠标拖拽旋转缩放模型,和控制台VTK行为完全一致。
四、核心概念理解
-
QVTKRenderWindowInteractor 它本身就是一个
QWidget,同时内部持有vtkRenderWindow+vtkRenderWindowInteractor。不要自己再外部新建
vtkRenderWindowInteractor,直接使用m_vtkWidget->GetInteractor()。 -
生命周期:控件销毁时,内部vtk对象会依靠
vtkSmartPointer自动释放;不要手动delete内部vtk对象。
五、高频踩坑(工业开发必看)
坑1:看不到模型/黑屏
- 忘记调用
GetInteractor()->Initialize() - 没有调用
ResetCamera(),相机位置不对,模型跑到视锥外面。
坑2:窗口缩放之后,画面不跟随重绘
QVTKRenderWindowInteractor内部已经处理Qt resize事件,一般不会; 如果手动修改数据,需要手动触发渲染:
m_vtkWidget->GetRenderWindow()->Render();
坑3:程序退出崩溃
- Qt窗口销毁顺序问题;不要在析构函数手动delete vtk对象,交给vtkSmartPointer管理。
- 不要在VTK回调里面直接操作Qt UI控件。
坑4:找不到QVTKRenderWindowInteractor头文件
- VTK编译没有打开
VTK_MODULE_ENABLE_VTK_GUISupportQt - CMakeLists没有链接
VTK::GUISupportQt
六、Qt信号槽 + VTK观察者回调打通(工程最重要)
VTK的
AddObserver回调跑在VTK内部,不可以直接操作Qt界面控件,会线程/事件循环冲突。 标准工程写法:VTK回调里面,emit Qt信号,把数据抛到Qt主线程槽函数去更新UI。
示例:监听鼠标点击事件,回调发Qt信号
// mainwindow.h 增加信号
signals:
void sigVtkMouseClick(double x,double y,double z);
// 自定义vtkCommand
class MyVtkCallback : public vtkCommand
{
public:
static MyVtkCallback* New(){ return new MyVtkCallback; }
void SetQObject(QObject* obj){ m_qObj = obj; }
virtual void Execute(vtkObject* caller, unsigned long eventId, void* vtkNotUsed(callData)) override
{
// vtk回调内部,不操作UI,只发射信号
emit m_qObj->sigVtkMouseClick(1,2,3);
}
private:
QObject* m_qObj{nullptr};
};
// MainWindow构造函数绑定
auto cb = vtkSmartPointer<MyVtkCallback>::New();
cb->SetQObject(this);
m_vtkWidget->GetInteractor()->AddObserver(vtkCommand::LeftButtonPressEvent, cb);
// 信号槽绑定,UI更新放在槽函数
connect(this,&MainWindow::sigVtkMouseClick,this,[](double x,double y,double z){
qDebug()<<"点击坐标"<<x<<y<<z;
});
关键原则:VTK回调只做数据采集,UI更新交给Qt槽函数。
七、多视图(四视图,机械软件经典)
多视图就是多个QVTKRenderWindowInteractor控件,放到不同的QWidget。 每个控件各自拥有一套独立vtkRenderer、独立相机。
注意:多个渲染窗口共享同一套vtkActor是可以的,Actor可以加到多个Renderer,不用重复拷贝PolyData,节省内存。
课后练习任务(动手写)
- 把上面示例跑通,Qt窗口里面显示模型。
- 增加右下角方向坐标轴
vtkOrientationMarkerWidget。 - 实现:VTK鼠标左键按下,回调发出Qt信号,界面打印日志。
接下来我们再讲:Update()、Modified()更新机制,以及内存坑。
你跑这个示例的时候遇到报错,可以直接贴出来。

浙公网安备 33010602011771号