VTK (Visualization Toolkit) 是一个强大的开源三维可视化库,而QT是一个流行的跨平台GUI框架。将两者结合可以创建功能丰富的科学可视化应用程序。
一、环境准备
首先确保已安装:
-
QT (5.9或更高版本)
-
VTK (9.0或更高版本)
-
CMake (构建工具)
二、基本集成方法
1. 使用QVTKOpenGLNativeWidget(推荐方式)
#include <QApplication>
#include <QSurfaceFormat>
#include <vtkActor.h>
#include <vtkConeSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <QVTKOpenGLNativeWidget.h>
int main(int argc, char** argv)
{
// 设置QT应用
QApplication app(argc, argv);
// 设置OpenGL版本和格式
QSurfaceFormat::setDefaultFormat(QVTKOpenGLNativeWidget::defaultFormat());
// 创建QT窗口和VTK部件
QMainWindow mainWindow;
QVTKOpenGLNativeWidget* vtkWidget = new QVTKOpenGLNativeWidget(&mainWindow);
// 创建VTK管线
vtkNew<vtkConeSource> cone;
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputConnection(cone->GetOutputPort());
vtkNew<vtkActor> actor;
actor->SetMapper(mapper);
vtkNew<vtkRenderer> renderer;
renderer->AddActor(actor);
vtkWidget->renderWindow()->AddRenderer(renderer);
// 设置窗口并显示
mainWindow.setCentralWidget(vtkWidget);
mainWindow.resize(800, 600);
mainWindow.show();
return app.exec();
}
2. 使用QVTKOpenGLWidget (旧版方式)
#include <QVTKOpenGLWidget.h>
// 其他包含与上面类似
// 使用方式与QVTKOpenGLNativeWidget类似
三、Make配置
CMake配置示例
cmake_minimum_required(VERSION 3.12)
project(VTK_QT_Example)
find_package(Qt5 REQUIRED COMPONENTS Widgets)
find_package(VTK REQUIRED)
add_executable(vtk_qt_example main.cpp)
target_link_libraries(vtk_qt_example
PRIVATE
Qt5::Widgets
${VTK_LIBRARIES}
)
或者 QMake配置示例(.pro文件)
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h
FORMS += \
mainwindow.ui
# Unix/Linux 配置
unix {
# 假设 VTK 安装在 /usr 目录下
VTK_DIR = /usr/lib/cmake/vtk-9.2
INCLUDEPATH += $$system(/usr/lib/vtk-9.2/include/vtk-9.2)
LIBS += -L$$system(/usr/lib/vtk-9.2/lib)
LIBS += -lGL
}
# Windows 配置
win32 {
INCLUDEPATH += $$PWD/'../../../../Program Files/VTK/include/vtk-9.2'
DEPENDPATH += $$PWD/'../../../../Program Files/VTK/include/vtk-9.2'
LIBS += -lopengl32
}
win32:CONFIG(release, debug|release):{
LIBS += -L$$PWD/'../../../../Program Files/VTK/lib/'
}
else:win32:CONFIG(debug, debug|release): {
LIBS += -L$$PWD/'../../../../Program Files/VTK/lib/'
}
else:unix:{
LIBS += -L$$PWD/'../../../../Program Files/VTK/lib/'
LIBS += -lGL
}
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
# 必需的核心 VTK 库
LIBS += -lvtksys-9.2
LIBS += -lvtkCommonColor-9.2
LIBS += -lvtkCommonCore-9.2
LIBS += -lvtkCommonDataModel-9.2
LIBS += -lvtkFiltersCore-9.2
LIBS += -lvtkInteractionStyle-9.2
LIBS += -lvtkRenderingCore-9.2
LIBS += -lvtkRenderingOpenGL2-9.2
LIBS += -lvtkViewsQt-9.2
LIBS += -lvtkGUISupportQt-9.2
LIBS += -lvtkRenderingAnnotation-9.2
# 可选: 用于数据处理和可视化的附加库
LIBS += -lvtkFiltersSources-9.2
LIBS += -lvtkFiltersGeneral-9.2
LIBS += -lvtkIOCore-9.2
LIBS += -lvtkIOXML-9.2
四、创建基本QT-VTK应用
1 创建QT项目
创建一个基本的QT Widgets Application项目。
2 修改main.cpp和mainwindow.h/mainwindow.cpp文件
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
// VTK 头文件
#include <vtkActor.h>
#include <vtkDataSetMapper.h>
#include <vtkDoubleArray.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPointData.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkScalarBarActor.h>
#include <vtkTriangle.h>
#include <vtkUnstructuredGrid.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkRendererCollection.h>
#include <vtkCamera.h>
// Qt VTK 集成组件
#include <QVTKOpenGLNativeWidget.h> // 或 QVTKOpenGLWidget
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void setupColorMap(int scheme = 0);
private:
void setupVTK();
void createSampleData();
void createToolBar();
QVTKOpenGLNativeWidget *vtkWidget;
vtkRenderWindow *renderWindow;
vtkRenderer *renderer;
vtkUnstructuredGrid *unstructuredGrid;
vtkActor *actor;
vtkDataSetMapper *mapper;
vtkScalarBarActor *scalarBar;
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QVBoxLayout>
#include <QToolBar>
#include <vtkLookupTable.h>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowTitle("VTK Stress Cloud");
resize(800, 600);
createToolBar();
// 创建中央部件和布局
QWidget *centralWidget = new QWidget(this);
QVBoxLayout *layout = new QVBoxLayout(centralWidget);
// 创建 VTK 部件
vtkWidget = new QVTKOpenGLNativeWidget(centralWidget);
layout->addWidget(vtkWidget);
setCentralWidget(centralWidget);
// 初始化 VTK
setupVTK();
}
MainWindow::~MainWindow()
{
// 清理 VTK 对象
if (renderWindow) renderWindow->Delete();
if (renderer) renderer->Delete();
if (unstructuredGrid) unstructuredGrid->Delete();
if (actor) actor->Delete();
if (mapper) mapper->Delete();
if (scalarBar) scalarBar->Delete();
delete ui;
}
void MainWindow::setupVTK()
{
// 创建渲染窗口和渲染器
renderWindow = vtkGenericOpenGLRenderWindow::New();
vtkWidget->setRenderWindow(renderWindow);
renderer = vtkRenderer::New();
renderWindow->AddRenderer(renderer);
//添加交互功能
vtkNew<vtkInteractorStyleTrackballCamera> style;
renderWindow->GetInteractor()->SetInteractorStyle(style);
// 创建示例数据
createSampleData();
// 设置背景色
vtkNew<vtkNamedColors> colors;
renderer->SetBackground(colors->GetColor3d("SlateGray").GetData());
// 重置相机并渲染
renderer->ResetCamera();
renderWindow->Render();
}
void MainWindow::createSampleData()
{
// 1. 创建点数据 (节点坐标)
vtkNew<vtkPoints> points;
points->InsertNextPoint(0.0, 0.0, 0.0);
points->InsertNextPoint(1.0, 0.0, 0.0);
points->InsertNextPoint(0.0, 1.0, 0.0);
points->InsertNextPoint(1.0, 1.0, 0.0);
points->InsertNextPoint(0.5, 0.5, 0.0); // 中心点
// 2. 创建非结构化网格
unstructuredGrid = vtkUnstructuredGrid::New();
unstructuredGrid->SetPoints(points);
// 创建三角形单元
vtkNew<vtkTriangle> triangle1;
triangle1->GetPointIds()->SetId(0, 0);
triangle1->GetPointIds()->SetId(1, 1);
triangle1->GetPointIds()->SetId(2, 4);
vtkNew<vtkTriangle> triangle2;
triangle2->GetPointIds()->SetId(0, 1);
triangle2->GetPointIds()->SetId(1, 3);
triangle2->GetPointIds()->SetId(2, 4);
vtkNew<vtkTriangle> triangle3;
triangle3->GetPointIds()->SetId(0, 3);
triangle3->GetPointIds()->SetId(1, 2);
triangle3->GetPointIds()->SetId(2, 4);
vtkNew<vtkTriangle> triangle4;
triangle4->GetPointIds()->SetId(0, 2);
triangle4->GetPointIds()->SetId(1, 0);
triangle4->GetPointIds()->SetId(2, 4);
unstructuredGrid->InsertNextCell(triangle1->GetCellType(), triangle1->GetPointIds());
unstructuredGrid->InsertNextCell(triangle2->GetCellType(), triangle2->GetPointIds());
unstructuredGrid->InsertNextCell(triangle3->GetCellType(), triangle3->GetPointIds());
unstructuredGrid->InsertNextCell(triangle4->GetCellType(), triangle4->GetPointIds());
// 3. 创建应力数据 (节点标量数据)
vtkNew<vtkDoubleArray> stressData;
stressData->SetNumberOfComponents(1);
stressData->SetName("Stress");
// 为每个节点添加应力值
stressData->InsertNextValue(10.0); // 节点0
stressData->InsertNextValue(20.0); // 节点1
stressData->InsertNextValue(15.0); // 节点2
stressData->InsertNextValue(25.0); // 节点3
stressData->InsertNextValue(50.0); // 中心节点4 (高应力区域)
unstructuredGrid->GetPointData()->SetScalars(stressData);
// 4. 创建映射器
mapper = vtkDataSetMapper::New();
mapper->SetInputData(unstructuredGrid);
// 设置颜色映射范围
double range[2];
stressData->GetRange(range);
mapper->SetScalarRange(range);
// 5. 创建演员
actor = vtkActor::New();
actor->SetMapper(mapper);
// 6. 创建标量条
scalarBar = vtkScalarBarActor::New();
scalarBar->SetLookupTable(mapper->GetLookupTable());
scalarBar->SetTitle("Stress (MPa)\n");
scalarBar->SetNumberOfLabels(5);
scalarBar->SetMaximumWidthInPixels(80);
scalarBar->SetMaximumHeightInPixels(200);
// 7. 添加到渲染器
renderer->AddActor(actor);
renderer->AddActor2D(scalarBar);
}
// 在主窗口类中添加:
void MainWindow::createToolBar()
{
QToolBar* toolBar = addToolBar("Controls");
QAction* zoomInAction = new QAction("Zoom In", this);
QAction* zoomOutAction = new QAction("Zoom Out", this);
//QAction* colorMapAction = new QAction("Color Map", this);
toolBar->addAction(zoomInAction);
toolBar->addAction(zoomOutAction);
//toolBar->addAction(colorMapAction);
connect(zoomInAction, &QAction::triggered, [this]() {
vtkCamera* camera = vtkWidget->renderWindow()->GetRenderers()->GetFirstRenderer()->GetActiveCamera();
camera->Zoom(1.2);
vtkWidget->renderWindow()->Render();
});
connect(zoomOutAction, &QAction::triggered, [this]() {
vtkCamera* camera = vtkWidget->renderWindow()->GetRenderers()->GetFirstRenderer()->GetActiveCamera();
camera->Zoom(0.8);
vtkWidget->renderWindow()->Render();
});
/*
connect(colorMapAction, &QAction::triggered, [this]() {
setupColorMap(2);
vtkWidget->renderWindow()->Render();
});
*/
}
void MainWindow::setupColorMap(int scheme)
{
if (!mapper) return;
vtkNew<vtkLookupTable> lut;
switch (scheme) {
case 0: // 蓝到红
lut->SetHueRange(0.667, 0.0);
break;
case 1: // 彩虹色
lut->SetHueRange(0.0, 0.667);
break;
case 2: // 灰度
lut->SetHueRange(0.0, 0.0);
lut->SetSaturationRange(0.0, 0.0);
lut->SetValueRange(0.2, 1.0);
break;
case 3: // 热力图
lut->SetHueRange(0.0, 0.2);
break;
}
lut->SetSaturationRange(1.0, 1.0);
lut->SetValueRange(1.0, 1.0);
lut->Build();
mapper->SetLookupTable(lut);
scalarBar->SetLookupTable(lut);
renderWindow->Render();
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <QSurfaceFormat>
int main(int argc, char *argv[])
{
// 设置 OpenGL 表面格式
QSurfaceFormat::setDefaultFormat(QVTKOpenGLNativeWidget::defaultFormat());
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h
FORMS += \
mainwindow.ui
# Unix/Linux 配置
unix {
# 假设 VTK 安装在 /usr 目录下
VTK_DIR = /usr/lib/cmake/vtk-9.2
INCLUDEPATH += $$system(/usr/lib/vtk-9.2/include/vtk-9.2)
LIBS += -L$$system(/usr/lib/vtk-9.2/lib)
LIBS += -lGL
}
# Windows 配置
win32 {
INCLUDEPATH += $$PWD/'../../../../Program Files/VTK/include/vtk-9.2'
DEPENDPATH += $$PWD/'../../../../Program Files/VTK/include/vtk-9.2'
LIBS += -lopengl32
}
win32:CONFIG(release, debug|release):{
LIBS += -L$$PWD/'../../../../Program Files/VTK/lib/'
}
else:win32:CONFIG(debug, debug|release): {
LIBS += -L$$PWD/'../../../../Program Files/VTK/lib/'
}
else:unix:{
LIBS += -L$$PWD/'../../../../Program Files/VTK/lib/'
LIBS += -lGL
}
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
# 必需的核心 VTK 库
LIBS += -lvtksys-9.2
LIBS += -lvtkCommonColor-9.2
LIBS += -lvtkCommonCore-9.2
LIBS += -lvtkCommonDataModel-9.2
LIBS += -lvtkFiltersCore-9.2
LIBS += -lvtkInteractionStyle-9.2
LIBS += -lvtkRenderingCore-9.2
LIBS += -lvtkRenderingOpenGL2-9.2
LIBS += -lvtkViewsQt-9.2
LIBS += -lvtkGUISupportQt-9.2
LIBS += -lvtkRenderingAnnotation-9.2
# 可选: 用于数据处理和可视化的附加库
LIBS += -lvtkFiltersSources-9.2
LIBS += -lvtkFiltersGeneral-9.2
LIBS += -lvtkIOCore-9.2
LIBS += -lvtkIOXML-9.2
运行结果:
五、常见问题解决
1. OpenGL上下文问题
如果遇到OpenGL相关错误,确保正确设置了OpenGL格式:
QSurfaceFormat::setDefaultFormat(QVTKOpenGLNativeWidget::defaultFormat());
2. 窗口大小变化问题
当QT窗口大小变化时,可能需要手动更新VTK渲染窗口:
void resizeEvent(QResizeEvent* event) override {
QVTKOpenGLNativeWidget::resizeEvent(event);
vtkWidget->renderWindow()->Render();
}
3. 交互问题
确保启用了交互器:
vtkNew<vtkRenderWindowInteractor> interactor;
interactor->SetRenderWindow(vtkWidget->renderWindow());
4. 内存泄漏
-
VTK使用引用计数,通常不需要手动删除对象
-
对于VTK与QT混合的对象,确保正确管理所有权
5. 渲染问题
-
如果出现黑屏,检查渲染器是否添加到渲染窗口
-
确保调用了
ResetCamera()
或设置了合适的相机位置
6.高DPI显示支持
启用QT的高DPI缩放
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
六、高级用法
1. 多视图布局
// 创建多个QVTKOpenGLNativeWidget
QVTKOpenGLNativeWidget* vtkWidget1 = new QVTKOpenGLNativeWidget;
QVTKOpenGLNativeWidget* vtkWidget2 = new QVTKOpenGLNativeWidget;
// 创建不同的渲染器和场景
// ...
// 添加到布局
QHBoxLayout* layout = new QHBoxLayout;
layout->addWidget(vtkWidget1);
layout->addWidget(vtkWidget2);
QWidget* centralWidget = new QWidget;
centralWidget->setLayout(layout);
mainWindow.setCentralWidget(centralWidget);
2. 信号与槽连接
// 连接VTK事件到QT槽
QObject::connect(vtkWidget, &QVTKOpenGLNativeWidget::mouseEvent,
[](QMouseEvent* event) {
// 处理鼠标事件
});
// 连接VTK交互事件到QT槽
class MyInteractorStyle : public vtkInteractorStyleTrackballCamera {
public:
static MyInteractorStyle* New();
vtkTypeMacro(MyInteractorStyle, vtkInteractorStyleTrackballCamera);
void OnLeftButtonDown() override {
// VTK交互代码
emit clicked();
}
Q_SIGNALS:
void clicked();
};
// 在QT中连接
MyInteractorStyle* style = MyInteractorStyle::New();
widget->interactor()->SetInteractorStyle(style);
QObject::connect(style, &MyInteractorStyle::clicked, [](){
qDebug() << "VTK view clicked";
});
七、注意事项
-
确保VTK和QT版本兼容
-
在Windows上可能需要设置平台插件路径
-
对于复杂场景,考虑使用vtkGenericOpenGLRenderWindow
-
调试时注意OpenGL版本和显卡驱动兼容性