前言
前面编译好了Qt5.9.3+VS2017x64+VTK8.2的开发环境,但是Qt结合VTK没有。
本篇Qt融合VTK,搭建基础Qt界面搭载VTK显示引擎的模板Demo。
Demo
QVTKWidget
QVTKWidget+MyVTKWidget
注意
这是上一篇install的结果:
建立模板工程(QVTKWidget.dll方式)
步骤一:建立vtkDemo工程
略
步骤二:模块化
文件夹modules,老规矩:
建立模块文件夹:
建立vtkWIdget.pri
工程包含pri:
建立VTKWidget界面类,方便提升:
步骤三:引入vtk的库和开发环境
先把install复制过来,标记好qt和msvc版本,为了以后多版本vtk预留(能就别少,作为代码模块集合):
添加进pri:
直接从文件夹复制进入pri,会是路径,再修改:
cpp
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
HEADERS += \
$$PWD/VTKWidget.h SOURCES += \ $$PWD/VTKWidget.cpp FORMS += \ $$PWD/VTKWidget.ui # vtk库包含 INCLUDEPATH += $$PWD/vtk-8.2.0-msvc2015x64-install/include \ $$PWD/vtk-8.2.0-msvc2015x64-install/include/vtk-8.2 LIBS += -L$$PWD/vtk-8.2.0-msvc2015x64-install/lib LIBS += -lvtkzlib-8.2 \ -lvtkChartsCore-8.2 \ -lvtkCommonColor-8.2 \ -lvtkCommonComputationalGeometry-8.2 \ -lvtkCommonCore-8.2 \ -lvtkCommonDataModel-8.2 \ -lvtkCommonExecutionModel-8.2 \ -lvtkCommonMath-8.2 \ -lvtkCommonMisc-8.2 \ -lvtkCommonSystem-8.2 \ -lvtkCommonTransforms-8.2 \ -lvtkDICOMParser-8.2 \ -lvtkDomainsChemistry-8.2 \ -lvtkDomainsChemistryOpenGL2-8.2 \ -lvtkdoubleconversion-8.2 \ -lvtkexodusII-8.2 \ -lvtkexpat-8.2 \ -lvtkFiltersAMR-8.2 \ -lvtkFiltersCore-8.2 \ -lvtkFiltersExtraction-8.2 \ -lvtkFiltersFlowPaths-8.2 \ -lvtkFiltersGeneral-8.2 \ -lvtkFiltersGeneric-8.2 \ -lvtkFiltersGeometry-8.2 \ -lvtkFiltersHybrid-8.2 \ -lvtkFiltersHyperTree-8.2 \ -lvtkFiltersImaging-8.2 \ -lvtkFiltersModeling-8.2 \ -lvtkFiltersParallel-8.2 \ -lvtkFiltersParallelImaging-8.2 \ -lvtkFiltersPoints-8.2 \ -lvtkFiltersProgrammable-8.2 \ -lvtkFiltersSelection-8.2 \ -lvtkFiltersSMP-8.2 \ -lvtkFiltersSources-8.2 \ -lvtkFiltersStatistics-8.2 \ -lvtkFiltersTexture-8.2 \ -lvtkFiltersTopology-8.2 \ -lvtkFiltersVerdict-8.2 \ -lvtkfreetype-8.2 \ -lvtkGeovisCore-8.2 \ -lvtkgl2ps-8.2 \ -lvtkglew-8.2 \ -lvtkGUISupportQt-8.2 \ -lvtkGUISupportQtSQL-8.2 \ -lvtkhdf5_hl-8.2 \ -lvtkhdf5-8.2 \ -lvtkImagingColor-8.2 \ -lvtkImagingCore-8.2 \ -lvtkImagingFourier-8.2 \ -lvtkImagingGeneral-8.2 \ -lvtkImagingHybrid-8.2 \ -lvtkImagingMath-8.2 \ -lvtkImagingMorphological-8.2 \ -lvtkImagingSources-8.2 \ -lvtkImagingStatistics-8.2 \ -lvtkImagingStencil-8.2 \ -lvtkInfovisCore-8.2 \ -lvtkInfovisLayout-8.2 \ -lvtkInteractionImage-8.2 \ -lvtkInteractionStyle-8.2 \ -lvtkInteractionWidgets-8.2 \ -lvtkIOAMR-8.2 \ -lvtkIOAsynchronous-8.2 \ -lvtkIOCityGML-8.2 \ -lvtkIOCore-8.2 \ -lvtkIOEnSight-8.2 \ -lvtkIOExodus-8.2 \ -lvtkIOExport-8.2 \ -lvtkIOExportOpenGL2-8.2 \ -lvtkIOExportPDF-8.2 \ -lvtkIOGeometry-8.2 \ -lvtkIOImage-8.2 \ -lvtkIOImport-8.2 \ -lvtkIOInfovis-8.2 \ -lvtkIOLegacy-8.2 \ -lvtkIOLSDyna-8.2 \ -lvtkIOMINC-8.2 \ -lvtkIOMovie-8.2 \ -lvtkIONetCDF-8.2 \ -lvtkIOParallel-8.2 \ -lvtkIOParallelXML-8.2 \ -lvtkIOPLY-8.2 \ -lvtkIOSegY-8.2 \ -lvtkIOSQL-8.2 \ -lvtkIOTecplotTable-8.2 \ -lvtkIOVeraOut-8.2 \ -lvtkIOVideo-8.2 \ -lvtkIOXML-8.2 \ -lvtkIOXMLParser-8.2 \ -lvtkjpeg-8.2 \ -lvtkjsoncpp-8.2 \ -lvtklibharu-8.2 \ -lvtklibxml2-8.2 \ -lvtkLocalExample-8.2 \ -lvtklz4-8.2 \ -lvtklzma-8.2 \ -lvtkmetaio-8.2 \ -lvtkNetCDF-8.2 \ -lvtkogg-8.2 \ -lvtkParallelCore-8.2 \ -lvtkpng-8.2 \ -lvtkproj-8.2 \ -lvtkpugixml-8.2 \ -lvtkRenderingAnnotation-8.2 \ -lvtkRenderingContext2D-8.2 \ -lvtkRenderingContextOpenGL2-8.2 \ -lvtkRenderingCore-8.2 \ -lvtkRenderingFreeType-8.2 \ -lvtkRenderingGL2PSOpenGL2-8.2 \ -lvtkRenderingImage-8.2 \ -lvtkRenderingLabel-8.2 \ -lvtkRenderingLOD-8.2 \ -lvtkRenderingOpenGL2-8.2 \ -lvtkRenderingQt-8.2 \ -lvtkRenderingVolume-8.2 \ -lvtkRenderingVolumeOpenGL2-8.2 \ -lvtksqlite-8.2 \ -lvtksys-8.2 \ -lvtktheora-8.2 \ -lvtktiff-8.2 \ -lvtkverdict-8.2 \ -lvtkViewsContext2D-8.2 \ -lvtkViewsCore-8.2 \ -lvtkViewsGeovis-8.2 \ -lvtkViewsInfovis-8.2 \ -lvtkViewsQt-8.2 # win平台的复制dll win32{ # copy vtk bin src_file = $$PWD/vtk-8.2.0-msvc2015x64-install/bin/* dst_file = $$OUT_PWD target_file = $$DESTDIR src_file ~= s,/,\\,g dst_file ~= s,/,\\,g target_file ~= s,/,\\,g system(xcopy $$src_file $$dst_file /y /s/q/e) system(xcopy $$src_file $$target_file /y /s/q/e) }
至此,运行环境引入好了。
步骤四:vkt引擎融入Qt界面
这里我们是直接通过QVTKWidget.h头文件和其lib、dll的方式引入:
建立模板工程(MyVTKWidget.cpp方式)
为了最大化兼容代码,这里QVTKWidget.dll就不动了,QVTKWidget源码里面实际是跟osgWidget一样,映射了窗口对于渲染器的操作,这里我们可以直接拿过来改个名字即可,所以先找到QVTKWidget.h和QVTKWIdget.cpp的源码,改成MyVTKWidget.h,MyVTKWidget.cpp:
复制改名:
加入源码:
修改里面的类名为MyVTKWidget,注意修改头文件宏:
编译通过,修改加入之后,出现一些错误:
这是因为代码默认定义了宏是导出dll的,所以需要修改,先去掉类的导出dll宏,然后编译,出错如下:
检查:
点开查看:
是因为这个类在这个库里面压根没有导出来cpp。
现在直接反过来去添加导出,修改源码(测试加头文件定义宏也报错,直接加入导出的代码吧):
然后重新编译:
安装并将库引过去替换试一试:
再次编译,解决了库定义的问题,还剩一个问题:
还是往回退到VS2017去搜索,搜索不到,这就是windows的函数,连接到对应的库就好了:
编译成功,运行失败:
怀疑是没包含dll,下面直接exe进行探测:
先补完qt的库:
然后点击运行:
是因为更新了这个lib,但是没有更新对应的dll过来:
Ok了,运行起来了,使用修改 源码大法可以 搞定,这样以后做其他的对映射操作就很方便了:
运行起来一个黑色一个白色:
去掉父类,测试左侧这种就是白色的。
为了确保可靠性,咱们还需要确认下,黑色和白色是否都是正常的,黑色肯定是正常的,写个常规代码:
跑起来后:
怀疑是哪个地方没有跑,导致初始化没有黑色,但是有场景的时候不影响。
建立模板工程(MyVTKWidget.cpp方式,失败,仅供参考)
为了最大化兼容代码,这里QVTKWidget.dll就不动了,QVTKWidget源码里面实际是跟osgWidget一样,映射了窗口对于渲染器的操作,这里我们可以直接拿过来改个名字即可,所以先找到QVTKWidget.h和QVTKWIdget.cpp的源码,改成MyVTKWidget.h,MyVTKWidget.cpp:
复制改名:
加入源码:
修改里面的类名为MyVTKWidget,注意修改头文件宏:
编译通过,修改加入之后,出现一些错误:
这是因为代码默认定义了宏是导出dll的,所以需要修改,先去掉类的导出dll宏,然后编译,出错如下:
检查是需要包含win:
继续编译:
#error: "No Target Architecture"
直接返回vs2017编译源码,查找编译的时候定义了哪些宏:
cpp
WIN32
_WINDOWS
NDEBUG
QT_NO_DEBUG
_CRT_SECURE_NO_DEPRECATE
_CRT_NONSTDC_NO_DEPRECATE
_CRT_SECURE_NO_WARNINGS
_SCL_SECURE_NO_DEPRECATE
_SCL_SECURE_NO_WARNINGS
VTK_IN_VTK
QT_WIDGETS_LIB
QT_GUI_LIB
QT_CORE_LIB
QT_UIPLUGIN_LIB
CMAKE_INTDIR="Release"
QVTKWidgetPlugin_EXPORTS
此方式行不通!!!
换个方式,退回去
注意
对比下osg和vtk的库大小:
源码
VTKWidget.h
cpp
#ifndef VTKWIDGET_H
#define VTKWIDGET_H #include <QWidget> #include "QVTKWidget.h" #include "MyVTKWidget.h" #include "vtkSphereSource.h" #include "vtkPolyDataMapper.h" #include "vtkActor.h" #include "vtkProperty.h" #include "vtkRenderer.h" #include "vtkRenderWindow.h" #include "vtkInteractorStyleTrackballCamera.h" #include "vtkOutputWindow.h" #include "vtkAutoInit.h" //VTK_MODULE_INIT(vtkRenderingOpenGL); VTK_MODULE_INIT(vtkRenderingOpenGL2); VTK_MODULE_INIT(vtkInteractionStyle); namespace Ui { class VTKWidget; } class VTKWidget : public QWidget { Q_OBJECT public: explicit VTKWidget(QWidget *parent = 0); ~VTKWidget(); protected: void initControl(); protected: void createSphere(QVTKWidget *pVTKWidget); // 临时代码,忽略代码规则 void createSphere(MyVTKWidget *pVTKWidget); // 临时代码,忽略代码规则 protected: void resizeEvent(QResizeEvent *event); private: Ui::VTKWidget *ui; private: QVTKWidget *_pQVTKWidget; MyVTKWidget *_pMyVTKWidget; }; #endif // VTKWIDGET_H
VTKWidget.cpp
cpp
#include "VTKWidget.h"
#include "ui_VTKWidget.h" #include <QDebug> #include <QDateTime> //#define LOG qDebug()<<__FILE__<<__LINE__ //#define LOG qDebug()<<__FILE__<<__LINE__<<__FUNCTION__ //#define LOG qDebug()<<__FILE__<<__LINE__<<QThread()::currentThread() //#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd") #define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") // QtCreator在msvc下设置编码也或有一些乱码,直接一刀切,避免繁琐的设置 #define MSVC #ifdef MSVC #define QSTRING(s) QString::fromLocal8Bit(s) #else #define QSTRING(s) QString(s) #endif VTKWidget::VTKWidget(QWidget *parent) : QWidget(parent), ui(new Ui::VTKWidget), _pQVTKWidget(0), _pMyVTKWidget(0) { ui->setupUi(this); initControl(); } VTKWidget::~VTKWidget() { delete ui; } void VTKWidget::initControl() { // 下面二选一,注意:这里必须在new之前设置好,new QVTKWidget窗口之后是无效的 vtkOutputWindow::GlobalWarningDisplayOff(); // 两段代码效果应该一致 vtkOutputWindow::SetGlobalWarningDisplay(0); // 设置消息登记显示,0-都不显示 _pQVTKWidget = new QVTKWidget(this); createSphere(_pQVTKWidget); _pMyVTKWidget = new MyVTKWidget(this); createSphere(_pMyVTKWidget); } void VTKWidget::createSphere(QVTKWidget *pVTKWidget) { // 1. 创建球体数据 vtkSphereSource* sphere = vtkSphereSource::New(); sphere->SetRadius(1.0); // 球体半径 sphere->SetThetaResolution(30); // 纬线方向分辨率 sphere->SetPhiResolution(30); // 经线方向分辨率 // 2. 创建映射器(连接数据与渲染) vtkPolyDataMapper* mapper = vtkPolyDataMapper::New(); mapper->SetInputConnection(sphere->GetOutputPort()); // 3. 创建演员(设置显示属性) vtkActor* actor = vtkActor::New(); actor->SetMapper(mapper); actor->GetProperty()->SetColor(0.3, 0.6, 0.9); // 蓝色球体 // 4. 创建渲染器并添加球体 vtkRenderer* renderer = vtkRenderer::New(); renderer->AddActor(actor); renderer->SetBackground(0.1, 0.1, 0.1); // 深灰色背景 // 5. 关联到QVTKWidget的渲染窗口 pVTKWidget->GetRenderWindow()->AddRenderer(renderer); // 6. 设置交互(支持鼠标旋转、缩放) vtkRenderWindowInteractor* interactor = vtkRenderWindowInteractor::New(); interactor->SetRenderWindow(pVTKWidget->GetRenderWindow()); interactor->SetInteractorStyle(vtkInteractorStyleTrackballCamera::New()); interactor->Initialize(); } void VTKWidget::createSphere(MyVTKWidget *pVTKWidget) { // 1. 创建球体数据 vtkSphereSource* sphere = vtkSphereSource::New(); sphere->SetRadius(1.0); // 球体半径 sphere->SetThetaResolution(30); // 纬线方向分辨率 sphere->SetPhiResolution(30); // 经线方向分辨率 // 2. 创建映射器(连接数据与渲染) vtkPolyDataMapper* mapper = vtkPolyDataMapper::New(); mapper->SetInputConnection(sphere->GetOutputPort()); // 3. 创建演员(设置显示属性) vtkActor* actor = vtkActor::New(); actor->SetMapper(mapper); actor->GetProperty()->SetColor(0.3, 0.6, 0.9); // 蓝色球体 // 4. 创建渲染器并添加球体 vtkRenderer* renderer = vtkRenderer::New(); renderer->AddActor(actor); renderer->SetBackground(0.1, 0.1, 0.1); // 深灰色背景 // 5. 关联到QVTKWidget的渲染窗口 pVTKWidget->GetRenderWindow()->AddRenderer(renderer); // 6. 设置交互(支持鼠标旋转、缩放) vtkRenderWindowInteractor* interactor = vtkRenderWindowInteractor::New(); interactor->SetRenderWindow(pVTKWidget->GetRenderWindow()); interactor->SetInteractorStyle(vtkInteractorStyleTrackballCamera::New()); interactor->Initialize(); } void VTKWidget::resizeEvent(QResizeEvent *event) { if(_pQVTKWidget) { _pQVTKWidget->setGeometry(rect().x(), rect().y(), rect().width() / 2 - 10, rect().height()); } if(_pMyVTKWidget) { _pMyVTKWidget->setGeometry(rect().width() / 2 + 10, rect().y(), rect().width() / 2 - 10, rect().height()); } }
工程模板v1.0.0
入坑
入坑一:运行渲染窗口弹出8.1remove
问题
出错点击关闭,提示截图图下:
尝试
添加头文件
初始化
然后结果:
调试窗口还是存在,关闭或者设置等级0,即可消息窗口输出即可。
解决
头文件
cpp
#include "vtkAutoInit.h"
初始化
cpp
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
添加关闭打印信息输出或者设置输出等级
cpp
// 下面二选一,注意:这里必须在new之前设置好,new QVTKWidget窗口之后是无效的
vtkOutputWindow::GlobalWarningDisplayOff(); // 两段代码效果应该一致 vtkOutputWindow::SetGlobalWarningDisplay(0); // 设置消息登记显示,0-都不显示