首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > VC/MFC >

基于VTK的MFC应用程序开发(一)

2013-03-27 
基于VTK的MFC应用程序开发(1)提到MFC一般都不陌生,大部分在校学生使用最多的应该就是它了。但是相对于Qt平

基于VTK的MFC应用程序开发(1)

        提到MFC一般都不陌生,大部分在校学生使用最多的应该就是它了。但是相对于Qt平台来说,MFC的机制比较复杂。当使用MFC平台进行VTK程序开发时,许多人可能没有头绪。这里结合一个实例讲一下如何在MFC平台下进行VTK程序开发。

        这里在MFC下实现一个基于VTK的单文档图像显示程序。通过这个程序,主要演示两个方面:一是怎样使用CMake将MFC程序与VTK结合;二是怎样在MFC程序中调用VTK类实现具体的功能。这个也是基于MFC和VTK进行软件开发的基础,搭好这个框架后,以后的工作就是垒砖了,相信通过前面的学习,垒砖已经小菜一碟了。

        在开始代码之前,这里提一下,相信许多人在网上查询这方面的资料的时候,有许多资料会讲到通过MFC中的开发环境(如Visual Studio 2008)设置VTK的包含路径和lib库路径等。但是这样配置对于一般用户来说比较复杂,每次开发新的工程时候,都要查找和设置这些库,既费时费力,又不利于程序的移植(例如换到另外一台机器,如果VTK编译路径不一致的话就会找不到库)。因此这里还是推荐大家使用CMake来管理程序。仅仅几行脚本代码就可以实现VTK库的配置,而且便于程序移植。

        现在开始一步步实现VTK和MFC的程序开发。首先建立一个单文档的MFC工程,工程名字为vtkSDI。这里与基于Qt的VTK程序开发稍微有点不同。先建立工程的目的是我们需要把由MFC自动生成的类加入到CMakeLists.txt中,方便管理。MFC单文档工程的建立比较简单,过程不再演示。工程文件如下所示,主要的类为CvtkSDIApp,CMainFrame,CvtkSDIDoc,CvtkSDIView和CAboutDlg五个。由于我们使用CMake来配置和生成工程,因此将工程目录下的工程文件删除,主要是.ncb,.sln,.vcproj,.user文件。

 基于VTK的MFC应用程序开发(一)

图1 MFC单文档工程的建立时所包含的文件

        下面编写CMakeLists.txt文件,将工程文件写入到CMakeLists.txt中并连接VTK动态库。VTK根据功能不同划分了多个不同的模块,每个模块都是一个库。因此在编写CMakeLists.txt文件的时候,可以根据需要添加相应的模块。

#----------------------------------------------cmake_minimum_required( VERSION 2.8 )project( vtkSDI ) #----------------------------------------------# 查找并包含VTK工具包find_package( VTK )if (VTK_FOUND)  include (${VTK_USE_FILE})else (VTK_FOUND)  message (FATAL_ERROR "Cannot build without VTK. Please set VTK_DIR")endif( VTK_FOUND )#----------------------------------------------# 这里添加本工程的文件# 主要分为两部分:# 一是新建的单文档程序中的非工程文件# 二是用户后续添加的类文件SET( PROJECT_SRCS    MainFrm.h    MainFrm.cpp    stdafx.h    stdafx.cpp    vtkSDI.h    vtkSDI.cpp    vtkSDIDoc.h    vtkSDIDoc.cpp    vtkSDIView.h    vtkSDIView.cpp    targetver.h    Resource.h    vtkSDI.rc    res/vtkSDI.rc2    res/vtkSDI.ico    res/vtkSDIDoc.ico    res/Toolbar.bmp    res/Toolbar256.bmp    ) #----------------------------------------------# 设置工程包含的vtk模块,这里根据需要加载对应的模块include("${VTK_DIR}/GUISupport/MFC/VTKMFCSettings.cmake")set( VTK_LIBS ${vtk_libraries}               vtkMFC              vtkIO              vtkRendering               vtkGraphics               vtkHybrid               vtkFiltering               vtkCommon               vtkImaging    )#----------------------------------------------ADD_EXECUTABLE( vtkSDI  WIN32  ${PROJECT_SRCS} )TARGET_LINK_LIBRARIES ( vtkSDI  ${VTK_LIBS} ) 

        需要注意的是在倒数第二行中需要加入WIN32,否则生成的工程在编译时会出现错误。第二个需要注意的是,由于工程是基于MFC的,需要连接vtkMFC库。完成CMakeLists.txt文件后,利用CMake设置相应的代码路径(存放工程源代码)和工程路径(存在生成的工程和文件),配置、生成当前工程,得到工程文件vtkSDI.sln。

        打开vtkSDI.sln并编译,编译后如无语法和链接错误,则可得到一个可运行的空工程。注意运行时可能会提示找不到dll文件错误,解决方法已在VTK与Qt整合的示例章节中说明,这里不再赘述。到此为止,基于MFC单文档工程的VTK编程框架已经搭建,接下来需要做的在该框架下调用VTK实现相应的功能。下面以图像的读取和显示为例进行说明。

        首先为vtkSDI工程添加一个菜单项,通过该菜单项加载图像。打开工程的资源视图Resource View,双击Menu中IDR_MAINFRAME菜单,右键单击FILE菜单下的Open项,为该项添加一个事件Add Event Handler,弹出如下窗口:

 基于VTK的MFC应用程序开发(一)

图2 添加MFC事件响应向导

        这里我们将该菜单的函数响应到CvtkSDIDoc文档类中,消息类型选择为COMMAND,点击Add and Edit按钮,完成消息的响应。该函数的作用是当用户选择该菜单时,弹出图像文件选择对话框,并将用户选择的图像文件加载。为此,我们需要为该类定义一个图像数据对象接收读入的图像数据。在CvtkSDIDoc头文件中添加如下代码,定义一个图像数据的智能指针:

vtkSmartPointer<vtkImageData> m_pImageData;

注意不要忘了添加头文件。在CvtkSDIDoc构造函数中对m_pImageData进行初始化,代码如下:

       m_pImageData =vtkSmartPointer<vtkImageData>::New();

       m_pImageData =NULL;

        然后在菜单响应函数OnFileOpen中,添加读取图像的代码。这里以jpg格式的图像为例进行说。VTK中读取jpg图像的类为vtkJPEGReader,代码如下:

void CvtkSDIDoc::OnFileOpen(){       // TODO: Add your command handler code here       CString FilePathName;        CFileDialog dlg( TRUE, NULL, NULL,                       OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,                       (LPCTSTR)_TEXT("JPG Files (*.jpg)|*.jpg|All Files (*.*)|*.*||"),                       NULL );        if(dlg.DoModal()==IDOK)       {              FilePathName=dlg.GetPathName();              vtkSmartPointer<vtkJPEGReader> reader = vtkSmartPointer<vtkJPEGReader>::New();              reader->SetFileName(FilePathName.GetBuffer(0));              reader->Update();              m_pImageData = reader->GetOutput();       }       else       {              return;       }}

        下面在CvtkSDIView类中实现图像的显示功能。这里我们使用VTK中的类vtkImageViewer2。该类提供了强大的图像显示功能,可以接受vtkImageData输入,通过设置交互对象vtkRenderWindowInteractor实现用户交互,如窗宽窗位调节,图像放缩等。这里首先在CvtkSDIView头文件中定义vtkImageViewer2对象和窗口交互对象vtkRenderWindowInteractor。

       vtkSmartPointer<vtkImageViewer2>                 m_pImageViewer;

       vtkSmartPointer<vtkRenderWindowInteractor>m_pRenderWindowInteractor;

        然后重载CvtkSDIView类的OnCreate()函数,在该函数中对定义的对象进行初始化,将MFC窗口句柄设置vtkImageViewer2的父窗口ID,以及设置vtkImageViewer2对象与vtkRenderWindowInteractor对象关联:

int CvtkSDIView::OnCreate(LPCREATESTRUCT lpCreateStruct){    if (CView::OnCreate(lpCreateStruct) == -1)           return -1;     // TODO:  Add your specialized creation code here    m_pImageViewer = vtkSmartPointer<vtkImageViewer2>::New();    m_pImageViewer->SetParentId(GetSafeHwnd());     m_pRenderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();    m_pImageViewer->SetupInteractor(m_pRenderWindowInteractor);    m_pRenderWindowInteractor->Start();    return 0;}

        为了使图像能够居中显示,需要每次在窗口大小改变时,设置m_pImageViewer的大小。这里重载CvtkSDIView类的函数OnSize(),当每次响应该函数时,将当前窗口的客户区域大小设置为m_pImageViewer的大小。

void CvtkSDIView::OnSize(UINT nType, int cx, int cy){    CView::OnSize(nType, cx, cy);     // TODO: Add your message handler code here    CRect rect;    GetClientRect(rect);    m_pImageViewer->SetSize(rect.Width(), rect.Height());}

        最后在OnDraw函数中实现图像渲染。在该函数中,将文档类中读入的图像数据设置vtkImageViewer2的输入,然后调用m_pImageViewer的Render函数开始渲染图像,并监听外部消息实现交互功能。

void CvtkSDIView::OnDraw(CDC* /*pDC*/){    CvtkSDIDoc* pDoc = GetDocument();    ASSERT_VALID(pDoc);    if (!pDoc)           return;    // TODO: add draw code for native data here    m_pImageViewer->SetInput(pDoc->m_pImageData);    m_pImageViewer->Render();}

        编译链接后即可执行程序,运行结果如下所示。另外还可以测试交互功能,如按住鼠标右键拖动鼠标或者滑动滚轮,实现图像的放缩功能;按住鼠标左键,拖动鼠标即可实现图像窗宽窗位的调节。

 基于VTK的MFC应用程序开发(一)

图3 程序运行结果

        从程序来看没有编译错误,而且正确显示图像。OK,关闭程序,这时意外出现了,在VS输出窗口中出现许多内存溢出,如下图所示:

基于VTK的MFC应用程序开发(一) 

图4 MFC&VTK程序内存溢出

        这样的内存溢出是因为VTK的DLL先于MFC的DLL加载。因此在CMakeLists.txt中加入下面代码对VTK的DLL进行延迟加载,代码如下:

VTK_MFC_ADD_DELAYLOAD_FLAGS(CMAKE_EXE_LINKER_FLAGS    vtkMFC.dll    vtkIO.dll    vtkRendering.dll    vtkGraphics.dll    vtkHybrid.dll    vtkFiltering.dll    vtkCommon.dll    vtkImaging.dll    )

 

        添加如上代码后,重新编译工程(rebuild),运行然后关闭工程,观察VS输出窗口中的输出信息,没有内存溢出错误,正常退出。

 

!!!!版权所有,转载请注明出处!!!!(@东灵工作室) 

热点排行