- vtk9.0.1
- vtk5.10.1
- CMake的版本要求
- 项目名
- 找到对应模块
- 载入文件
- 添加.cpp文件
- 加入依赖库的lib
- The location of the UseVTK.cmake file.
- 方式一:多个源文件之间用空格隔开
- 方式二:用变量
- cmake版本
- 工程的名字
- 找Qt、vtk相关包,而且是必须找到
- 加入使用VTK、Qt的相关文件
- 程序所有源文件
- Qt的UI文件
- 包含所有含有Q_OBJECT的头文件
- qt4_wrap_ui通过Qt的uic.exe生成UI文件对应的ui_xxx.h文件,并将生成的ui_xxx.h文件列表存储于变量Project_UIS_H中
- qt_wrap_cpp通过Qt的moc.exe将包含Q_OBJECT的头文件生成对应的moc_xxx.cxx文件,并存储在变量PROJECT_MOC_HDRS中
- 引用文件夹
- 加入源代码与头文件,编译成CombineQtAndVTK.exe
- 依赖库
- —————————————————————————————————————————————————————————————————-
- Windows平台下,构建程序运行时所需的目录
- Windows平台下使用VS时,创建两个正确设置环境变量的批处理文件
- 分别是StartVS_Debug.bat和StartVS_Release.bat文件
- substitute again
- include “ProjectMainWindow.h”
- include
- include
- include
- include
- include
- include
- include
- include
- include
- include
vtk9.0.1
cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
project(cone)
find_package(VTK COMPONENTS
CommonCore
FiltersSources
InteractionStyle
RenderingOpenGL2 QUIET)
if (NOT VTK_FOUND)
#找VTK的路径
message("fatal Skipping cone: ${VTK_NOT_FOUND_MESSAGE}")
return ()
endif()
message (STATUS "VTK_VERSION: ${VTK_VERSION}")
# 添加所有代码
add_executable(cone Cone.cxx )
# 链接第三方库
target_link_libraries(cone PRIVATE ${VTK_LIBRARIES})
# VTK_LIBRARIES变量由VTK的CMake文件提供
# vtk_module_autoinit is needed
vtk_module_autoinit(
TARGETS cone
MODULES ${VTK_LIBRARIES}
)
vtk5.10.1
HelloVtk
- 编写源代码:
D:\VTK\Examples\Chap01\1.3_TestVTKInstall.cpp
- 编写CMake文件:
D:\VTK\Examples\Chap01\CMakeLists.txt
```CMake的版本要求
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)项目名
PROJECT( Chap01 )
找到对应模块
FIND_PACKAGE( VTK REQUIRED )
载入文件
INCLUDE( ${VTK_USE_FILE} )
添加.cpp文件
ADD_EXECUTABLE( 1.3_TestVTKInstall 1.3_TestVTKInstall.cpp)
加入依赖库的lib
TARGET_LINK_LIBRARIES( 1.3_TestVTKInstall vtkRendering vtkCommon )
3. 然后在cmake-gui中设置以下内容
1. `Where to build the binaries`:`D:\VTK\Examples\Chap01\bin`
1. 编译环境:VS17、x64
点击Advanced视图,会显示出来以下几项
1. `CMAKE_INSTALL_PREFIX`:默认路径为`C:\Program Files\XXX`(XXX由CMakeLists里的project指定)
1. `VTK_DIR` VTK编译目录
1. 准确地说,是VTKConfig.cmake文件所在的完整路径
1. 一般情况下,编译完VTK以后,用CMake配置VTK的工程时,VTK_DIR选项的值都会自动填充。如果CMake找不到,或者找不到的不是想要的VTK版本,可以自己换别的路径
关于DLL文件,可以在VS项目里配置
1. 方法一:Properties > Configuration Properties > Debugging > Environment 输入VTK的dll路径,即`PATH=%PATH%;D:\VTK-5.10-bin\bin\Debug`
1. 方法二:右键项目 > Properties > Configuration Properties > Debugging > Working Directory > `D:\VTK-5.10-bin\bin\Debug`
<a name="G5L1O"></a>
#### CMAKE_MINIMUM_REQUIRED
指定构建工程时所需的CMake版本要求
CMAKE_MINIMUM_REQUIRED( VERSION major[.minorp[.patch[.tweak]]] [FATAL_ERROR] )
1. 第一个参数`VERSION`是必选参数,且为大写(CMake命令名不区分大小写,为了统一描述,尽量都使用大写)
1. 第二个参数为指定CMAKE的版本号
1. 第三个参数为可选参数,且为CMake内置关键字`FATAL_ERROR`,如果构建工程所用CMake版本没有达到要求,配置过程就会出现以下错误提示,并终止工程构建过程
![image.png](https://cdn.nlark.com/yuque/0/2021/png/1465826/1619580627343-5f0bd123-51b2-441c-a298-f7c5fce7e1e6.png#crop=0&crop=0&crop=1&crop=1&height=124&id=hYTt0&margin=%5Bobject%20Object%5D&name=image.png&originHeight=197&originWidth=443&originalType=binary&ratio=1&size=60138&status=done&style=none&width=278)
<a name="PQDsg"></a>
#### 工程名PROJECT
用该命名指定工程名称,可指定工程支持的语言,支持语言的参数为可选。默认是C\C++
PROJECT(工程名 [CXX][C][Java])
该命令还隐含两个CMake内置变量:
1. `<projectName>_BINARY_DIR`或`PROJECT_BINARY_DIR`,在此示例中,值为`D:\VTK\Examples\Chap01\bin`
1. `<projectName>_SOURCE_DIR`或`PROJECT_SOURCE_DIR`,在此示例中,值为`D:\VTK\Examples\Chap01\Chap01`
为了统一起见,以后直接用CMake的内置变量`PROJECT_BINARY_DIR`与`PROJECT_SOURCE_DIR`,这样即使改了工程名称,这两个变量的值也会相应变化
该命令第一个参数也隐含了一个CMake内置变量`PROJECT_NAME`,可以通过`${PROJECT_NAME}`来取变量的值。在这个例子中,`${PROJECT_NAME}`即为`Chap01`
<a name="byBdy"></a>
#### 找到对应模块FIND_PACKAGE
FIND_PACKAGE用于搜索并加载外部工程,其隐含的变量为`<package>_FOUND`,用于标示是否搜索到所需的工程。
FIND_PACKAGE(
1. 参数`[REQUIRED]`表示所要搜索到的外部工程对本工程来说是必须的,如果没有搜索到,CMake会终止整个工程构建过程。
以VTK为例,`FIND_PACKAGE`命令搜索的就是VTK的配置文件VTKConfig.cmake。<br />在VTK自带的示例目录里的CMakeLists.txt中有以下的CMake脚本语句(VTK-5.10\Examples\Tutorial\Step1\Cxx\CMakeLists.txt)
FIND_PACKAGE(VTK REQUIRED) IF(NOT VTK_USE_RENDERING) MESSAGE(FATAL_ERROR “Example ${PROJECT_NAME} requires VTK_USE_RENDERING”) ENDIF(NOT VTK_USE_RENDERING)
以上四行的作用与`FIND_PACKAGE( VTK REQUIRED )`实现的功能是一样的。
<a name="jpQkK"></a>
#### 载入文件或模块INCLUDE
指定载入一个文件或者模块
INCLUDE(
<a name="ZsATQ"></a>
##### 如果指定的是模块,那么将在`CMAKE_MODULE_PATH`中搜索这个模块并载入
1. 变量`CMAKE_MODULE_PATH`指的是搜索CMake模块的目录
1. 安装完CMake以后,在CMake的安装目录下(默认是`C:\Program Files(x84)\CMake 2.8`)可以找到CMake已定义的模块,路径为`C:\Program Files(x86)\CMake 2.8\share\cmake-2.8\Modules`
<a name="uJ7mL"></a>
##### `INCLUDE( ${VTK_USE_FILE} )`的意义
本例中指定的是VTK模块,在`C:\Program Files(x86)\CMake 2.8\share\cmake-2.8\Modules`下存在`FindVTK.cmake`文件,其中定义了变量`VTK_USE_FILE`(在VTK编译目录`D:\VTK\VTK-5.10-bin\VTKConfig.cmake`文件中也可以看到)
The location of the UseVTK.cmake file.
SET(VTK_USE_FILE “D:/VTK/VTK-5.10-bin/UseVTK.cmake”)
所以,`INCLUDE( ${VTK_USE_FILE} )`即等于`INCLUDE(D:/VTK/VTK-5.10-bin/UseVTK.cmake)`
<a name="BBGHe"></a>
#### 生成可执行文件ADD_EXECUTABLE
ADD_EXECUTABLE(
定义这个工程会生成一个文件名为`<name>`的可执行文件,相关的源文件通过source1、source2、...、sourceN列出
如果有多个源文件,有两种方式
方式一:多个源文件之间用空格隔开
ADD_EXECUTABLE(projectname source1.cpp source2.cpp source3.cpp)
方式二:用变量
SET(projectname_src source1.cpp source2.cpp source3.cpp) ADD_EXECUTABLE(projectname ${projectname_src})
<a name="1ba71144"></a>
#### 链接依赖库的lib TARGET_LINK_LIBRARIES
指定生成可执行文件时需要链接哪些文件
1. 参数<target>的名称必须与`ADD_EXECUTABLE`中指定的`<name>`一致
1. 在写这些链接的函数库时不需要带".lib"后缀
TARGET_LINE_LIBRARIES(
`TARGET_LINK_LIBRARIES( 1.3_TestVTKInstall vtkRendering vtkCommon )`
<a name="O9h3u"></a>
##### 为什么本例中要链接vtkRendering.lib文件
1. .cpp中使用了`vtkRenderWindow`和`vtkSmartPointer`这两个类
1. 查找这两个类的头文件所在路径,分别是`VTK-5.10-src\Rendering`和`VTK-5.10-src\Common`
1. 在VTK编译的目录中又能找到`vtkRendering.lib`和`vtkCommon.lib`这两个文件
1. 所以是否可以断定类`vtkRenderWindow`和`vtkSmartPointer`的接口就分别定义在这两个文件中呢?
<a name="BuI1W"></a>
##### 可以直接使用VTK_LIBRARIES自定义变量
在VTKConfig.cmake文件中定义了一个变量VTK_LIBRARIES
SET(VTK_LIBRARIES “vtkCommon;vtkFiltering;vtkImageing;vtkGraphics;vtkGenericFiltering;vtkIO;vtkRendering;vtkVolumeRendering;vtkHybrid;vtkWidgets;vtkInfos;vtkGeovis;vtkViews;vtkCharts” )
所以,可以不需要一一列出所要的链接的函数库,可以直接引用变量值:`${VTK_LIBRARIES}`来代替`vtkRendering vtkCommon`
<a name="uk1BT"></a>
## 用CMake管理Qt与VTK工程
cmake版本
cmake_minimun_required(VERSION 2.8)
工程的名字
project(CombineQtAndVtk)
找Qt、vtk相关包,而且是必须找到
find_package(VTK REQUIRED) find_package(Qt4 REQUIRED)
加入使用VTK、Qt的相关文件
include(${VTK_USE_FILE}) include(${QT_USE_FILE})
程序所有源文件
set(PROJECT_SRCS main.cpp ProjectMainWindow.cpp )
Qt的UI文件
set(PROJECT_UIS ProjectMainWindow.ui )
包含所有含有Q_OBJECT的头文件
set(PROJECT_MOC_HDRS ProjectMainWindow.h )
qt4_wrap_ui通过Qt的uic.exe生成UI文件对应的ui_xxx.h文件,并将生成的ui_xxx.h文件列表存储于变量Project_UIS_H中
qt4_wrap_ui(PROJECT_UIS_H ${PROJECT_UIS} )
qt_wrap_cpp通过Qt的moc.exe将包含Q_OBJECT的头文件生成对应的moc_xxx.cxx文件,并存储在变量PROJECT_MOC_HDRS中
qt4_wrap_cpp(PROJECT_MOC_SRCS ${PROJECT_MOC_HDRS} )
引用文件夹
生成的moc_xxx.cxx和ui_xxx.h等文件是存放在CMake的”Where build the binaries”里指定的目录里,所以必须将这些路径包含进来
include_directories(${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${VTK_DIR} )
加入源代码与头文件,编译成CombineQtAndVTK.exe
add_executable(CombineQtAndVTK ${PROJECT_SRCS} ${PROJECT_UIS_H} ${PROJECT_MOC_SRCS} )
依赖库
target_line_libraries(CombineQtAndVTK ${VTK_LIBRARIES} QVTK )
<a name="ySKaO"></a>
#### 找不到dll
运行VTK应用程序之后,有时会遇到类似的问题:找不到*.dll<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1465826/1619596271525-a33a7793-c6f6-4bd6-8782-37651655b74f.png#crop=0&crop=0&crop=1&crop=1&height=85&id=e8yTd&margin=%5Bobject%20Object%5D&name=image.png&originHeight=169&originWidth=440&originalType=binary&ratio=1&size=44222&status=done&style=none&width=220)
<a name="ev1WZ"></a>
##### 方法一:将dll拷贝到exe同级目录下
缺点:繁琐
<a name="NB3d8"></a>
##### 方法二:将dll拷贝到Windows系统目录下
Windows系统目录:`C:\Windows\system32`或者`C:\Windows\system`<br />缺点:多版本不好管理
<a name="Hn6vN"></a>
##### 方法三:CMake里加命令,构建工程时把系统的Path环境变量加载进来,使得在工程启动之前加载这些环境变量
1. CMakeLists.txt:在CMakeLists.txt文件的最后添加代码
—————————————————————————————————————————————————————————————————-
Windows平台下,构建程序运行时所需的目录
SET(PROJECT_RUNTIME_PATH “${VTK_LIBRARY_DIRS}/@VS_BUILD_TYPE@;${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/@VS_BUILD_TYPE@” ) IF(QT4_FOUND) SET(PROJECT_RUNTIME_PATH “${PROJECT_RUNTIME_PATH};${QT_LIBRARY_DIR}/../bin”) ENDIF()
INCLUDE(CreateWindowsBatchScript.cmake)
Windows平台下使用VS时,创建两个正确设置环境变量的批处理文件
分别是StartVS_Debug.bat和StartVS_Release.bat文件
IF(WIN32) SET(VSSOLUTION_FILE “${PROJECT_BINARY_DIR}/${PROJECT_NAME}.sln”) FOREACH(VS_BUILD_TYPE debug release) CreateWindowsBatchScript(“${CMAKE_SOURCE_DIR}/StartVS.bat.in” ${PROJECT_BINARY_DIR}/StartVS${VS_BUILD_TYPE}.bat ${VS_BUILD_TYPE}) ENDFOREACH() ENDIF(WIN32)
2. CreateWindowsBatchScript.cmake
FUNCTION(CreateWindowsBatchScript in out build_type) IF(VTK_DIR) SET(VTK_BIN_DIR “${VTK_DIR}/bin/${build_type}”) ELSE() SET(VTK_BIN_DIR) ENDIF()
SET(VS_BUILD_TYPE ${build_type}) CONFIGURE_FILE(${in} ${out} @ONLY)
substitute again
CONFIGURE_FILE(${out} ${out} @ONLY) ENDFUNCTION()
3. StartVS.bat.in
@set CL=/D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE @set LINK=/LARGEADDRESSAWARE
PATH=@PROJECT_RUNTIME_PATH@;%PATH% “@VS_SOLUTION_FILE@”
工程通过CMake的configure、generate以后,即可生成StartVS_Debug.bat和StartVS_release.bat两个脚本文件。
1. 如果需要编译、运行Debug版本的工程,可双击StartVS_debug.bat文件打开对应的工程
1. Release版本也类似,一旦这种方式打开相应的工程,就不用担心出现“无法加载xxx.dll文件”的错误
<a name="TcOeY"></a>
## 用QVTKWidget整合Qt和VTK
可以使用VTK提供的QVTKWidget类实现Qt与VTK的整合,该类继承自QWidget,所以可以把它当作Qt的Widget来使用,甚至可以在Qt Designer里像Qt的其他标准控件一样具有拖拽功能
除了QVTKWidget类之外,VTK还提供大量与Qt相关的类。著名的ParaView软件就是基于VTK和Qt编写的。
<a name="8yaWq"></a>
##### 在Qt Designer里集成QVTKWidget控件
![image.png](https://cdn.nlark.com/yuque/0/2021/png/1465826/1619604089173-f1800605-8041-43b3-9c69-d2c6c5fca22f.png#crop=0&crop=0&crop=1&crop=1&height=272&id=ORWYs&margin=%5Bobject%20Object%5D&name=image.png&originHeight=543&originWidth=744&originalType=binary&ratio=1&size=283711&status=done&style=none&width=372)
<a name="gabwx"></a>
##### 一个简单的VTK/QT程序
![image.png](https://cdn.nlark.com/yuque/0/2021/png/1465826/1619604228025-4f0001e7-991c-4a4d-895d-e324e78ef305.png#crop=0&crop=0&crop=1&crop=1&height=175&id=pyqXl&margin=%5Bobject%20Object%5D&name=image.png&originHeight=349&originWidth=310&originalType=binary&ratio=1&size=83829&status=done&style=none&width=155)
1. ProjectMainWindow.h
```cpp
#ifndef Project_MainWindow_H
#define Project_MainWindow_H
#include <QMainWindow>
#include "ui_ProjectMainWindow.h"
#include <vtkSmartPointer.h>
class vtkImageViewer2;
class vtkRenderer;
class vtkEventQtSlotConnect;
class vtkObject;
class vtkCommand;
class ProjectMainWindow : public QMainWindow, public Ui::ProjectMainWindow
{
Q_OBJECT
public:
ProjectMainWindow();
~ProjectMainWindow();
private slots:
//响应打开图像文件的槽函数
void onOpenSlot();
//响应鼠标移动的消息,实时输出鼠标的当前位置
void updateCoords(vtkObject* obj);
private:
vtkSmartPointer< vtkImageViewer2 > m_pImageViewer;
vtkSmartPointer< vtkRenderer > m_pRenderder;
vtkEventQtSlotConnect* m_Connections;
};
#endif
- ProjectMainWindow.cpp
```cpp
include “ProjectMainWindow.h”
include
include
include
include
include
include
include
include
include
include
ProjectMainWindow::ProjectMainWindow() { setupUi(this);
m_pImageViewer = vtkSmartPointer< vtkImageViewer2 >::New();
m_pRenderder = vtkSmartPointer< vtkRenderer >::New();
// 设置m_QVTKWidget的渲染器
m_QVTKWidget->GetRenderWindow()->AddRenderer(m_pRenderder);
//连接打开的信号与相应的槽
connect( m_OpenAction, SIGNAL( triggered() ), this, SLOT( onOpenSlot() ) );
m_Connections = vtkEventQtSlotConnect::New();
m_Connections->Connect(m_QVTKWidget->GetRenderWindow()->GetInteractor(),
vtkCommand::MouseMoveEvent,
this,
SLOT(updateCoords(vtkObject*)));
}
ProjectMainWindow::~ProjectMainWindow() { }
void ProjectMainWindow::onOpenSlot() { QString filter; filter = “JPEG image file (.jpg .jpeg)”;
QDir dir;
QString fileName = QFileDialog::getOpenFileName( this, QString(tr("打开图像")), dir.absolutePath() , filter );
if ( fileName.isEmpty() == true ) return;
// 支持带中文路径的读取
QByteArray ba = fileName.toLocal8Bit();
const char *fileName_str = ba.data();
// 用vtkJPEGReader读取JPG图像
vtkSmartPointer<vtkJPEGReader> reader = vtkSmartPointer<vtkJPEGReader>::New();
reader->SetFileName(fileName_str);
// 将reader的输出作为m_pImageViewer的输入,并设置m_pImageViewer与渲染器m_pRenderer的关联
m_pImageViewer->SetInput(reader->GetOutput());
m_pImageViewer->UpdateDisplayExtent();
m_pImageViewer->SetRenderWindow(m_QVTKWidget->GetRenderWindow());
m_pImageViewer->SetRenderer(m_pRenderder);
m_pImageViewer->SetupInteractor(m_QVTKWidget->GetRenderWindow()->GetInteractor());
m_pImageViewer->SetSliceOrientationToXY(); //默认就是这个方向的
m_pImageViewer->GetImageActor()->InterpolateOff();
m_pRenderder->ResetCamera();
m_pRenderder->DrawOn();
m_QVTKWidget->GetRenderWindow()->Render();
}
void ProjectMainWindow::updateCoords(vtkObject obj) { // 获取交互器 vtkRenderWindowInteractor iren = vtkRenderWindowInteractor::SafeDownCast(obj);
// 获取鼠标的当前位置
int event_pos[2];
iren->GetEventPosition(event_pos);
QString str;
str.sprintf("x=%d : y=%d", event_pos[0], event_pos[1]);
m_StatusBar->showMessage(str);
用vtkEventQtSlotConnect实现VTK事件与Qt槽的连接
vtkEventQtSlotConnect类可以实现VTK事件与Qt的槽函数的连接
VTK事件主要在vtkCommand.h文件里定义,包括鼠标单击、双击、移动等。
比如,可以通过响应VTK的事件来实现一个简单的功能:当移动鼠标时,在窗口上显示当前鼠标的像素坐标值,代码如下: