VTK开发笔记(二):Qt5.9.3+VS2017x64+VTK8.2创建兼容dll和嵌入源码窗口两种方式的Qt嵌入VTK8.2模板Demo

0 阅读6分钟

前言

  前面编译好了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-都不显示

  在这里插入图片描述