前言
前面编译好了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,会是路径,再修改:
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编译源码,查找编译的时候定义了哪些宏:
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
#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
#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,即可消息窗口输出即可。
解决
头文件
#include "vtkAutoInit.h"
初始化
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
添加关闭打印信息输出或者设置输出等级
// 下面二选一,注意:这里必须在new之前设置好,new QVTKWidget窗口之后是无效的
vtkOutputWindow::GlobalWarningDisplayOff(); // 两段代码效果应该一致
vtkOutputWindow::SetGlobalWarningDisplay(0); // 设置消息登记显示,0-都不显示