基于VTK的Qt应用程序开发

基于VTK的Qt应用程序开发

分类: VTK应用示例 6570人阅读 评论(25) 收藏 举报

目录(?)[+]

VTK附带的程序示例中大多是基于控制台的,作为可视化开发工具包,VTK也可以与很多流行的GUI开发工具整合,比如MFC、Qt(题外话:Qt已经被Digia从诺基亚手中收购了,Qt现在的链接是: http://qt-project.org/,也有已经编译好的版本: http://code.google.com/p/qt-msvc-installer/downloads/list直接下载安装。可能因为大学课程里会教授MFC的内容,一些非计算机专业的会偏向于采用MFC,个人觉得,对于非计算机专业而言,如果一定要选择一种GUI工具做开发的话,建议用Qt,容易上手,学习周期短)、FLTK( http://www.fltk.org/,FLTK也是跨平台的,是一种比较轻便的GUI工具,VTK官方发布版本没有提供对FLTK的接口,但可以借助类 vtkFlRenderWindowInteractor,来实现VTK与FLTK的整合)等等,VTK的源码目录里(VTK-5.10\Examples\GUI)包含有VTK与Qt、MFC、Tcl等工具的整合。考虑到VTK对Qt的特殊照顾(VTK提供了很多针对Qt的类可以非常方便地与Qt整合),以及Qt自身的一些性质(如易用性、跨平台等),我们参考了VTK自带的一些例子,给出了VTK与Qt整合的详细步骤。

1.   CMakeLists.txt文件

我们已经知道了VTK工程的管理是用CMake的,而Qt自身有qmake工具,如果对于一些小工程而言,单纯的Qt程序用qmake来构建工程,确实很方便,但如果随着工程复杂度的增加以及工程依赖其他的函数库时,使用CMake来管理工程或许是一个明智的选择。而且随着你对CMake语法的了解,你会发现用CMake来管理工程是一件非常棒的事情。

我们先看看对于单纯的Qt工程,怎么来写CMakeLists.txt脚本文件。

1.1 用CMake来管理Qt工程

官方对于这个话题给出的解释在这里。我们引用一下这篇博文的图,然后给出每句CMakeLists.txt脚本的注释,结合这个图以及脚本的注释,相信你应该能明白了。

 

[plain] view plain copy
  1. #----------------------------------------------  
  2. # 下面这两行,没什么好解释的  
  3. cmake_minimum_required( VERSION 2.8 )  
  4. project( YourProjectName )  
  5.    
  6. #----------------------------------------------  
  7. # 下面这两行,也没什么好解释的  
  8. find_package( Qt4 REQUIRED )  
  9. include( ${QT_USE_FILE} )  
  10.    
  11. #----------------------------------------------  
  12. # 程序所有源文件。<TODO:在此处添加源文件>  
  13. # 定义变量Project_SRCS,其值为所列的文件列表  
  14. SET( Project_SRCS  
  15.     main.cpp  
  16.   )  
  17.    
  18. #----------------------------------------------  
  19. # 程序所有UI文件。<TODO:在此处添加UI文件>  
  20. # 定义变量Project_UIS,其值为所列的文件列表  
  21. SET( Project_UIS  
  22.     YourQtWindows.ui  
  23. )  
  24.    
  25. #----------------------------------------------  
  26. # 所有包含Q_OBJECT的头文件。<TODO:在此处添加头文件>  
  27. # 定义变量Project_MOC_HDRS,其值为所列的文件列表  
  28. SET( Project_MOC_HDRS  
  29.     YourQtProjectFiles.h  
  30. )  
  31.    
  32. #-----------------------------------------------  
  33. # 通过Qt的uic.exe生成UI文件对应的ui_XXXX.h文件  
  34. # 将生成的ui_XXXX.h文件放在变量Project_UIS_H里,  
  35. # QT4_WRAP_UI就是干这个事情。  
  36. QT4_WRAP_UI( Project_UIS_H ${Project_UIS} )  
  37.    
  38. #-----------------------------------------------  
  39. # 通过Qt的moc.exe生成包含Q_OBJECT的头文件对应的  
  40. # moc_XXXX.cxx文件,将生成的moc_XXXX.cxx文件放在  
  41. # 变量Project_MOC_SRCS里。QT4_WRAP_CPP就是干这个事情。  
  42. QT4_WRAP_CPP( Project_MOC_SRCS ${Project_MOC_HDRS} )  
  43.    
  44. #-----------------------------------------------  
  45. # Qt的MOC和UIC程序生成的moc_XXXX.cxx和ui_XXXX.h  
  46. # 等文件是存放在CMake的“Where to build the binaries"  
  47. # 里指定的目录里,所以必须都这些路径包含进来。  
  48. INCLUDE_DIRECTORIES( ${Project_SOURCE_DIR}  
  49.                      ${CMAKE_CURRENT_BINARY_DIR}  
  50.                    )  
  51.    
  52. #-----------------------------------------------                            
  53. # Qt程序如果有资源文件(*.qrc),要包含资源文件,  
  54. # 然后用Qt的rcc.exe生成相应的qrc_XXXX.cpp文件。  
  55. # QT4_ADD_RESOURCES就是干这个事情。  
  56. SET( Project_RCCS YourProject.qrc)  
  57. QT4_ADD_RESOURCES( Project_RCC_SRCS ${Project_RCCS})  
  58.    
  59. #-----------------------------------------------  
  60. # 根据程序的cpp文件、头文件以及中间生成的ui_XXXX.h、  
  61. # moc_XXXX.cxx、qrc_XXXX.cxx等生成可执行文件,并链接  
  62. # Qt的动态库(Qt的动态库都定义在QT_LIBRARIES变量里了)  
  63. ADD_EXECUTABLE( YourProjectName  
  64.                 ${Project_SRCS}  
  65.                 ${Project_UIS_H}  
  66.                 ${Project_MOC_SRCS}  
  67.                 ${Project_RCC_SRCS}                             
  68.               )  
  69. TARGET_LINK_LIBRARIES ( YourProjectName ${QT_LIBRARIES} )  

1.2 用CMake来管理Qt与VTK工程

我们在上面的基础上添加VTK相关的CMake脚本文件,如下:

[plain] view plain copy
  1. #----------------------------------------------------------------------------------  
  2. cmake_minimum_required( VERSION 2.8 )  
  3. project( CombineQtAndVTK )  
  4.    
  5. #----------------------------------------------------------------------------------  
  6. find_package( VTK REQUIRED )  
  7. find_package( Qt4 REQUIRED )  
  8.    
  9. include( ${VTK_USE_FILE} )  
  10. include( ${QT_USE_FILE} )  
  11.    
  12. #----------------------------------------------------------------------------------  
  13. SET( PROJECT_SRCS  
  14.     main.cpp  
  15.     ProjectMainWindow.cpp  
  16.     )  
  17.    
  18. SET( PROJECT_UIS  
  19.     ProjectMainWindow.ui  
  20. )  
  21.    
  22. SET( PROJECT_MOC_HDRS  
  23.   ProjectMainWindow.h  
  24. )  
  25.    
  26. #----------------------------------------------------------------------------------  
  27. QT4_WRAP_UI( PROJECT_UIS_H  
  28.              ${PROJECT_UIS}  
  29.            )  
  30.    
  31. QT4_WRAP_CPP( PROJECT_MOC_SRCS  
  32.               ${PROJECT_MOC_HDRS}  
  33.             )  
  34.    
  35. #----------------------------------------------------------------------------------  
  36. INCLUDE_DIRECTORIES( ${PROJECT_SOURCE_DIR}  
  37.                      ${CMAKE_CURRENT_BINARY_DIR}  
  38.                      ${VTK_DIR}  
  39.                    )  
  40.    
  41. ADD_EXECUTABLE( CombineQtAndVTK  
  42.                 ${PROJECT_SRCS}  
  43.                 ${PROJECT_UIS_H}  
  44.                 ${PROJECT_MOC_SRCS}  
  45.               )  
  46.    
  47. TARGET_LINK_LIBRARIES ( CombineQtAndVTK  
  48.   ${VTK_LIBRARIES}  
  49.   QVTK  
  50.   )  

以上的脚本除了红色字体标注的跟1.1注释的不太像之外,其他的都一样,不再解释。

1.3 CMake脚本里增加工程环境变量的加载

很多非计算机专业的用户在使用VTK进行编程时,经常会碰到类似下图所示的一些错误。

 

碰到这样的错误以后,可能很多用户就不知道怎么处理了,其实上面的提示信息已经写得非常清楚了,就是缺少“vtkCommon.dll”文件。但是又有人会说:我的电脑里明明有这个文件存在啊,为什么会找不到呢?

一般的解决方法可能是:

方法一:将缺少的dll文件全部拷贝的工程的Debug或者Release目录下(拷贝的时候要注意你编译的VTK是Debug版本的还是Release版本的,如果拷错的话,又会出现其他不可预知的错误了)。但是这个方法是你每建一个工程,运行工程之前得把缺少的动态库文件又要拷贝过去,如果你不嫌麻烦的话,可以采用。

方法二:将缺少的dll文件全部拷贝到Windows系统的目录下,即C:\Windows\system32或者C:\Windows\system目录下,这个方法是你拷贝一次,以后再基于你拷贝的VTK动态库的工程运行的时候问题都解决了。但它同样有一个问题,假如你电脑里的VTK升级成别的版本,重新编译了一份动态库,或者是同时在你电脑里编译了好几个版本的VTK,这个时候就有点凌乱了。

为什么这两种方法都可以解决问题?原来动态编译的程序在启动的时候,会搜索程序所在的目录以及系统环境变量PATH所列的目录,如果这些目录有该程序需要的动态库时,就加载它们,如果没有,就提示无法加载相应动态库的错误。

可以在工程的CMakeLists.txt文件里添加一些脚本,把系统的PATH环境变量作一些更改,在工程启动之前加载这些环境变量。也就是(在工程的CMakeLists.txt最后添加):

[plain] view plain copy
  1. #-----------------------------------------------------------------------------------  
  2. # Construct a list of paths containing runtime directories for project applications on Windows  
  3. set(PROJECT_RUNTIME_PATH  "${VTK_LIBRARY_DIRS}/@VS_BUILD_TYPE@;  
  4. ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/@VS_BUILD_TYPE@"  
  5.     )  
  6. if(QT4_FOUND)  
  7.   set(PROJECT_RUNTIME_PATH "${PROJECT_RUNTIME_PATH};${QT_LIBRARY_DIR}/../bin")  
  8. endif()  
  9.    
  10. include(CreateWindowsBatchScript.cmake)  
  11.    
  12. # If we are under Windows, create two batch files which correctly  
  13. # set up the environment for the application and for Visual Studio  
  14. if(WIN32)  
  15.   set(VS_SOLUTION_FILE "${PROJECT_BINARY_DIR}/${PROJECT_NAME}.sln")  
  16.   foreach(VS_BUILD_TYPE debug release)  
  17.     CreateWindowsBatchScript("${CMAKE_SOURCE_DIR}/StartVS.bat.in"  
  18.       ${PROJECT_BINARY_DIR}/StartVS_${VS_BUILD_TYPE}.bat  
  19.       ${VS_BUILD_TYPE})  
  20.   endforeach()  
  21. endif(WIN32)  


以上的脚本也不是特别复杂,但提到了两个文件:CreateWindowsBatchScript.cmake以及StartVS.bat.in。这两个文件的内容分别是:

CreateWindowsBatchScript.cmake:

 

[plain] view plain copy
  1. function(CreateWindowsBatchScript in out build_type)  
  2.   if(VTK_DIR)  
  3.     set(VTK_BIN_DIR "${VTK_DIR}/bin/${build_type}")  
  4.   else()  
  5.     set(VTK_BIN_DIR)  
  6.   endif()  
  7.    
  8.   set(VS_BUILD_TYPE ${build_type})  
  9.   configure_file(${in} ${out} @ONLY)  
  10.   # substitute again  
  11.   configure_file(${out} ${out} @ONLY)  
  12. endfunction()  

StartVS.bat.in

 

[plain] view plain copy
  1. @set CL=/D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE  
  2. @set LINK=/LARGEADDRESSAWARE  
  3.    
  4. PATH=@PROJECT_RUNTIME_PATH@;%PATH%  
  5. "@VS_SOLUTION_FILE@"  

将工程通过CMake的configure->generate以后,即可生成StartVS_debug.bat和StartVS_release.bat两个脚本文件。如果你要编译、运行Debug版本的工程,即双击StartVS_debug.bat文件打开对应的工程,同理,Release版本的也一样。一旦按这种方式打开相应的工程,就不用再担心类似“无法加载***.dll文件”的错误了。如果你的程序还增加了ITK等函数库,也可以照着上面的脚本作相应的修改。

注意:使用时将CreateWindowsBatchScript.cmakeStartVS.bat.in两个文件与工程的CMakeLists.txt放在同一级目录里。即类似下图的目录结构:

 

2.   用QVTKWidget整合Qt&VTK

Qt与VTK的整合可以使用VTK提供的类QVTKWidget,看这个类名就知道这个类其实就是一个Qt里的Widget (QVTKWidget派生自QWidget),所以可以把它当作普通的Qt里的Widget来使用,甚至可以在Qt Designer里像Qt的其他标准控件一样拖来拖去。

2.1 在Qt Designer里集成

要实现QVTKWidget在Qt Designer里像Qt的其他标准控件一样拖来拖去,需要把编译生成的QVTKWidgetPlugin.dll/QVTKWidgetPlugin.lib(Release版本)复制到Qt的安装目录里的plugins\designer目录下。完了以后,你会在Qt Designer里面看到如下的控件:

 

2.2 读入一幅图像,并在Qt界面上显示

接下来,我们来完成一个小功能,就是读入一幅JPG图像,然后在Qt界面上,用VTK来显示。功能非常简单,程序也非常简单。上代码:

ProjectMainWindow.h:

  1. #ifndef Project_MainWindow_H  
  2. #define Project_MainWindow_H  
  3.    
  4. #include <QMainWindow>  
  5. #include "ui_ProjectMainWindow.h"  
  6.    
  7. #include <vtkSmartPointer.h>  
  8.    
  9. class vtkImageViewer2;  
  10. class vtkRenderer;  
  11.    
  12.    
  13. class ProjectMainWindow : public QMainWindow, public Ui::ProjectMainWindow  
  14. {  
  15.        Q_OBJECT  
  16.    
  17. public:  
  18.        ProjectMainWindow();  
  19.        ~ProjectMainWindow();  
  20.    
  21. private slots:  
  22.        //响应打开图像文件的槽函数  
  23.        void onOpenSlot();  
  24.    
  25. private:  
  26.        vtkSmartPointer< vtkImageViewer2 > m_pImageViewer;  
  27.        vtkSmartPointer< vtkRenderer > m_pRenderder;  
  28. };  
  29.    
  30. #endif  

ProjectMainWindow.cpp:

  1. #include "ProjectMainWindow.h"  
  2.    
  3. #include <QFileDialog>  
  4. #include <QDir>  
  5.    
  6. #include <vtkRenderWindow.h>  
  7. #include <vtkRenderer.h>  
  8. #include <vtkImageViewer2.h>  
  9. #include <QVTKWidget.h>  
  10. #include <vtkJPEGReader.h>  
  11. #include <vtkImageActor.h>  
  12.    
  13. ProjectMainWindow::ProjectMainWindow()  
  14. {  
  15.        setupUi(this);  
  16.    
  17.        m_pImageViewer  = vtkSmartPointer< vtkImageViewer2 >::New();  
  18.        m_pRenderder      = vtkSmartPointer< vtkRenderer >::New();  
  19.    
  20.        // 设置m_QVTKWidget的渲染器  
  21.        m_QVTKWidget->GetRenderWindow()->AddRenderer(m_pRenderder);  
  22.    
  23.        //连接打开的信号与相应的槽  
  24.        connect( m_OpenAction, SIGNAL( triggered() ), this, SLOT( onOpenSlot() ) );  
  25. }  
  26.    
  27. ProjectMainWindow::~ProjectMainWindow()  
  28. {  
  29. }  
  30.    
  31. void ProjectMainWindow::onOpenSlot()  
  32. {  
  33.        QString filter;  
  34.        filter = "JPEG image file (*.jpg *.jpeg)";  
  35.    
  36.        QDir dir;  
  37.        QString fileName = QFileDialog::getOpenFileName( this,   
  38.                                  QString(tr("打开图像")), dir.absolutePath() , filter );  
  39.        if ( fileName.isEmpty() == true ) return;  
  40.    
  41.        // 支持带中文路径的读取  
  42.        QByteArray ba = fileName.toLocal8Bit();  
  43.        const char *fileName_str = ba.data();  
  44.    
  45.        // 用vtkJPEGReader读取JPG图像  
  46.        vtkSmartPointer<vtkJPEGReader> reader = vtkSmartPointer<vtkJPEGReader>::New();  
  47.        reader->SetFileName(fileName_str);  
  48.    
  49.        // 将reader的输出作为m_pImageViewer的输入,并设置m_pImageViewer与渲染器m_pRenderer的关联  
  50.        m_pImageViewer->SetInput(reader->GetOutput());  
  51.        m_pImageViewer->UpdateDisplayExtent();  
  52.        m_pImageViewer->SetRenderWindow(m_QVTKWidget->GetRenderWindow());  
  53.        m_pImageViewer->SetRenderer(m_pRenderder);  
  54.        m_pImageViewer->SetupInteractor(m_QVTKWidget->GetRenderWindow()->GetInteractor());  
  55.        m_pImageViewer->SetSliceOrientationToXY(); //默认就是这个方向的  
  56.        m_pImageViewer->GetImageActor()->InterpolateOff();  
  57.        m_pRenderder->ResetCamera();  
  58.        m_pRenderder->DrawOn();  
  59.        m_QVTKWidget->GetRenderWindow()->Render();  
  60. }  

程序运行结果:

 

2.3 用vtkEventQtSlotConnect实现VTK事件与Qt槽的连接

类vtkEventQtSlotConnect可以实现VTK的事件与Qt的槽函数的连接,VTK的事件主要在vtkCommand.h文件里定义,包括鼠标单击、鼠标双击、鼠标移动等等,如:

vtkCommand::ProgressEvent

vtkCommand::ErrorEvent

vtkCommand::WarningEvent

vtkCommand::PickEvent

vtkCommand::StartPickEvent

vtkCommand::EndPickEvent

vtkCommand::CharEvent

vtkCommand::KeyPressEvent

vtkCommand::KeyReleaseEvent

vtkCommand::LeftButtonPressEvent

vtkCommand::LeftButtonReleaseEvent

vtkCommand::MouseMoveEvent

……

具体的代码实现:

  1. private slots:  
  2.        //响应鼠标移动的消息,实时输出鼠标的当前位置  
  3.        void updateCoords(vtkObject* obj);  
  4.    
  5. private:  
  6.        vtkEventQtSlotConnect* m_Connections;  


源文件:

  1. //构造函数里:  
  2.        m_Connections = vtkEventQtSlotConnect::New();  
  3.        m_Connections->Connect(m_QVTKWidget->GetRenderWindow()->GetInteractor(),  
  4.               vtkCommand::MouseMoveEvent,  
  5.               this,  
  6.               SLOT(updateCoords(vtkObject*)));  
  7.    
  8. //槽函数的实现  
  9. void ProjectMainWindow::updateCoords(vtkObject* obj)  
  10. {  
  11.        // 获取交互器  
  12.        vtkRenderWindowInteractor* iren = vtkRenderWindowInteractor::SafeDownCast(obj);  
  13.    
  14.        // 获取鼠标的当前位置  
  15.        int event_pos[2];  
  16.        iren->GetEventPosition(event_pos);  
  17.    
  18.        QString str;  
  19.        str.sprintf("x=%d : y=%d", event_pos[0], event_pos[1]);  
  20.        m_StatusBar->showMessage(str);  
  21. }  


程序运行结果:

 

示例代码及该博文文档下载地址:http://download.csdn.net/detail/www_doling_net/5137375

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值