QT+VTK+Visual Studio 2010联合开发
由于开发VTK程序是需要的GUI环境需求比较苛刻,传统的MFC框架在开发简单的GUI程序时还行,稍微复杂一点的程序就显得生硬。因此在开源社区里,开发VTK的GUI程序时,普遍采用QT。以下简单描述这三者的关系。
准备工作,这三者应该提前安装,建议遵循安装顺序为先Visual Studio 2010,再按装QT,再按装CMake,最后安装VTK,因为在用CMake编译VTK工程时就可以一次性配置了,免得做重复性工作。
1.Visual Studio 2010,他是编译器,因为VTK本身也是C/C++程序,当然需要C/C++的编译器,当然在开发程序过程中也可以起到编辑器的作用;
2.QT用来设计界面,不仅提供自身的空间,而且通过CMake配置之后,还可以生成VTK为QT生成的支持空间QVTKWidget;
3.VTK提供了大量的类,这些类为我们提供了形形色色的对象还有算法,这些类都是用C/C++语言编写的,因此开发VTK最好的语言应该是C/C++,也可以用Python语言显得简单。
安装QT的关键就是要做好环境变量的Path的设置,关于这一点网上有很多博客,建议读者参考。以下简要介绍开发QT+VTK程序的步骤:
第一步,用QT Designer设计好界面,如下图所示:
第二步,三个文件的编写:
1.ProjectMainWindow.h
/**********************************************************************
文件名: ProjectMainWindow.h
Copyright (c) 张晓东, 罗火灵. All rights reserved.
更多信息请访问:
http://www.vtkchina.org (VTK中国)
http://blog.csdn.net/www_doling_net (东灵工作室)
**********************************************************************/
#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
2.ProjectMainWindow.cpp
/**********************************************************************
文件名: ProjectMainWindow.cpp
Copyright (c) 张晓东, 罗火灵. All rights reserved.
更多信息请访问:
http://www.vtkchina.org (VTK中国)
http://blog.csdn.net/www_doling_net (东灵工作室)
**********************************************************************/
#include "ProjectMainWindow.h"
#include <QFileDialog>
#include <QDir>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkImageViewer2.h>
#include <QVTKWidget.h>
#include <vtkJPEGReader.h>
#include <vtkImageActor.h>
#include <vtkEventQtSlotConnect.h>
#include <vtkCommand.h>
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);
}
3.main.cpp
/**********************************************************************
文件名: main.cpp
Copyright (c) 张晓东, 罗火灵. All rights reserved.
更多信息请访问:
http://www.vtkchina.org (VTK中国)
http://blog.csdn.net/www_doling_net (东灵工作室)
**********************************************************************/
#include "ProjectMainWindow.h"
#include <QTextCodec>
//程序发布时,可以不要注释以下语句,编译的时候就不会带控制台输出窗口
//#pragma comment( linker, "/subsystem:windows /entry:mainCRTStartup" )
int main( int argc, char **argv )
{
QApplication *app = new QApplication(argc, argv);
QTextCodec::setCodecForTr(QTextCodec::codecForName("GB2312"));
ProjectMainWindow *window = new ProjectMainWindow();
window->show();
return app->exec();
};
第三步:编写CMakeLists.txt文件:
#**********************************************************************
#
# Copyright (c) 张晓东, 罗火灵. All rights reserved.
# 更多信息请访问:
# http://www.vtkchina.org (VTK中国)
# http://blog.csdn.net/www_doling_net (东灵工作室)
#
#**********************************************************************
CMAKE_MINIMUM_REQUIRED( VERSION 2.8 )
PROJECT( Qt )
#----------------------------------------------------------------------------------
FIND_PACKAGE( VTK REQUIRED )
FIND_PACKAGE( Qt4 REQUIRED )
INCLUDE( ${VTK_USE_FILE} )
INCLUDE( ${QT_USE_FILE} )
#----------------------------------------------------------------------------------
SET( PROJECT_SRCS
main.cpp
ProjectMainWindow.cpp
)
SET( PROJECT_UIS
ProjectMainWindow.ui
)
SET( PROJECT_MOC_HDRS
ProjectMainWindow.h
)
#----------------------------------------------------------------------------------
QT4_WRAP_UI( PROJECT_UIS_H
${PROJECT_UIS}
)
QT4_WRAP_CPP( PROJECT_MOC_SRCS
${PROJECT_MOC_HDRS}
)
#----------------------------------------------------------------------------------
INCLUDE_DIRECTORIES( ${PROJECT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${VTK_DIR}
)
ADD_EXECUTABLE( Qt
${PROJECT_SRCS}
${PROJECT_UIS_H}
${PROJECT_MOC_SRCS}
)
TARGET_LINK_LIBRARIES ( Qt
${VTK_LIBRARIES}
QVTK
)
#-----------------------------------------------------------------------------------------------------------------------------------
# Construct a list of paths containing runtime
# directories for project applications on 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)
# If we are under Windows, create two batch files which correctly
# set up the environment for the application and for Visual Studio
IF(WIN32)
SET(VS_SOLUTION_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)
其中CMakeLists又包含了两个脚本:CreateWindowsBatchScript.cmake和StartVS.bat.in,关于这两个脚本的内容,需要对编程有深入的了解之后才能明白,此处读者就照原样编写,其内容如下:
CreateWindowsBatchScript.cmake:
#######################################################################
#
# Copyright (c) 张晓东, 罗火灵. All rights reserved.
# 更多信息请访问:
# http://www.vtkchina.org (VTK中国)
# http://blog.csdn.net/www_doling_net (东灵工作室)
#
#######################################################################
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()
StartVS.bat.in
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: Copyright (c) 张晓东, 罗火灵. All rights reserved.
:: 更多信息请访问:
:: http://www.vtkchina.org (VTK中国)
:: http://blog.csdn.net/www_doling_net (东灵工作室)
::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
@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”生成工程。我在配置的时候出现了错误,经查后发现是CMake自动识别QT_QMAKE_EXECUTABLE的路径时出错,因此手动输入这个这个路径,然后重新配置,就正确了。如下图所示,
第六步:编译,有CMake配置后生成的bin文件夹中的内容如下:
此时可以双击打开Qt.sln文件,打开VS2010后直接编译,编译没错,但是在运行时,因为是动态共享库的方式,所以会提示很多的.dll文件找不到,解决此问题的办法就是在VTK编译的二进制文件找到需要的.dll文件,将他们一个个添加到本工程的Debug文件夹下,然后在运行,就可以成功了。
还有一个办法是,在上图中直接双击StartVS_debug.bat文件,打开VS2010IDE环境,然后编译运行,都能通过,结果如下所示:
还有一个相似的文件StartVS_release.bat文件,它们的作用是一样的,但是由它编译出的是release版本的工程,如果在安装VTK编译VTK项目时编译过release版本的二进制文件,此时就可以选择它,否则是无法编译通过的。其中缘由,读者自行思考。
参考文献张晓东,罗火灵.《VTK图形图像开发进阶》.机械工业出版社