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整合的詳細步驟。app
咱們已經知道了VTK工程的管理是用CMake的,而Qt自身有qmake工具,若是對於一些小工程而言,單純的Qt程序用qmake來構建工程,確實很方便,但若是隨着工程複雜度的增長以及工程依賴其餘的函數庫時,使用CMake來管理工程或許是一個明智的選擇。並且隨着你對CMake語法的瞭解,你會發現用CMake來管理工程是一件很是棒的事情。ide
咱們先看看對於單純的Qt工程,怎麼來寫CMakeLists.txt腳本文件。函數
官方對於這個話題給出的解釋在這裏。咱們引用一下這篇博文的圖,而後給出每句CMakeLists.txt腳本的註釋,結合這個圖以及腳本的註釋,相信你應該能明白了。工具
#----------------------------------------------學習 # 下面這兩行,沒什麼好解釋的開發工具 cmake_minimum_required( VERSION 2.8 )字體 project( YourProjectName )ui
#----------------------------------------------this # 下面這兩行,也沒什麼好解釋的 find_package( Qt4 REQUIRED ) include( ${QT_USE_FILE} )
#---------------------------------------------- # 程序全部源文件。<TODO:在此處添加源文件> # 定義變量Project_SRCS,其值爲所列的文件列表 SET( Project_SRCS main.cpp )
#---------------------------------------------- # 程序全部UI文件。<TODO:在此處添加UI文件> # 定義變量Project_UIS,其值爲所列的文件列表 SET( Project_UIS YourQtWindows.ui )
#---------------------------------------------- # 全部包含Q_OBJECT的頭文件。<TODO:在此處添加頭文件> # 定義變量Project_MOC_HDRS,其值爲所列的文件列表 SET( Project_MOC_HDRS YourQtProjectFiles.h )
#----------------------------------------------- # 經過Qt的uic.exe生成UI文件對應的ui_XXXX.h文件 # 將生成的ui_XXXX.h文件放在變量Project_UIS_H裏, # QT4_WRAP_UI就是幹這個事情。 QT4_WRAP_UI( Project_UIS_H ${Project_UIS} )
#----------------------------------------------- # 經過Qt的moc.exe生成包含Q_OBJECT的頭文件對應的 # moc_XXXX.cxx文件,將生成的moc_XXXX.cxx文件放在 # 變量Project_MOC_SRCS裏。QT4_WRAP_CPP就是幹這個事情。 QT4_WRAP_CPP( Project_MOC_SRCS ${Project_MOC_HDRS} )
#----------------------------------------------- # Qt的MOC和UIC程序生成的moc_XXXX.cxx和ui_XXXX.h # 等文件是存放在CMake的「Where to build the binaries" # 裏指定的目錄裏,因此必須都這些路徑包含進來。 INCLUDE_DIRECTORIES( ${Project_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} )
#----------------------------------------------- # Qt程序若是有資源文件(*.qrc),要包含資源文件, # 而後用Qt的rcc.exe生成相應的qrc_XXXX.cpp文件。 # QT4_ADD_RESOURCES就是幹這個事情。 SET( Project_RCCS YourProject.qrc) QT4_ADD_RESOURCES( Project_RCC_SRCS ${Project_RCCS})
#----------------------------------------------- # 根據程序的cpp文件、頭文件以及中間生成的ui_XXXX.h、 # moc_XXXX.cxx、qrc_XXXX.cxx等生成可執行文件,並連接 # Qt的動態庫(Qt的動態庫都定義在QT_LIBRARIES變量裏了) ADD_EXECUTABLE( YourProjectName ${Project_SRCS} ${Project_UIS_H} ${Project_MOC_SRCS} ${Project_RCC_SRCS} ) TARGET_LINK_LIBRARIES ( YourProjectName ${QT_LIBRARIES} ) |
咱們在上面的基礎上添加VTK相關的CMake腳本文件,以下:
#---------------------------------------------------------------------------------- cmake_minimum_required( VERSION 2.8 ) project( CombineQtAndVTK )
#---------------------------------------------------------------------------------- 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( CombineQtAndVTK ${PROJECT_SRCS} ${PROJECT_UIS_H} ${PROJECT_MOC_SRCS} )
TARGET_LINK_LIBRARIES ( CombineQtAndVTK ${VTK_LIBRARIES} QVTK ) |
以上的腳本除了紅色字體標註的跟1.1註釋的不太像以外,其餘的都同樣,再也不解釋。
不少非計算機專業的用戶在使用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最後添加):
#----------------------------------------------------------------------------------- # 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) |
以上的腳本也不是特別複雜,但提到了兩個文件:CreateWindowsBatchScript.cmake以及StartVS.bat.in。這兩個文件的內容分別是:
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() |
@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兩個腳本文件。若是你要編譯、運行Debug版本的工程,即雙擊StartVS_debug.bat文件打開對應的工程,同理,Release版本的也同樣。一旦按這種方式打開相應的工程,就不用再擔憂相似「沒法加載***.dll文件」的錯誤了。若是你的程序還增長了ITK等函數庫,也能夠照着上面的腳本做相應的修改。
注意:使用時將CreateWindowsBatchScript.cmake和StartVS.bat.in兩個文件與工程的CMakeLists.txt放在同一級目錄裏。即相似下圖的目錄結構:
Qt與VTK的整合可使用VTK提供的類QVTKWidget,看這個類名就知道這個類其實就是一個Qt裏的Widget (QVTKWidget派生自QWidget),因此能夠把它看成普通的Qt裏的Widget來使用,甚至能夠在Qt Designer裏像Qt的其餘標準控件同樣拖來拖去。
要實現QVTKWidget在Qt Designer裏像Qt的其餘標準控件同樣拖來拖去,須要把編譯生成的QVTKWidgetPlugin.dll/QVTKWidgetPlugin.lib(Release版本)複製到Qt的安裝目錄裏的plugins\designer目錄下。完了之後,你會在Qt Designer裏面看到以下的控件:
接下來,咱們來完成一個小功能,就是讀入一幅JPG圖像,而後在Qt界面上,用VTK來顯示。功能很是簡單,程序也很是簡單。上代碼:
ProjectMainWindow.h:
#ifndef Project_MainWindow_H #define Project_MainWindow_H
#include <QMainWindow> #include "ui_ProjectMainWindow.h"
#include <vtkSmartPointer.h>
class vtkImageViewer2; class vtkRenderer;
class ProjectMainWindow : public QMainWindow, public Ui::ProjectMainWindow { Q_OBJECT
public: ProjectMainWindow(); ~ProjectMainWindow();
private slots: //響應打開圖像文件的槽函數 void onOpenSlot();
private: vtkSmartPointer< vtkImageViewer2 > m_pImageViewer; vtkSmartPointer< vtkRenderer > m_pRenderder; };
#endif |
ProjectMainWindow.cpp:
#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>
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() ) ); }
ProjectMainWindow::~ProjectMainWindow() { }
void ProjectMainWindow::onOpenSlot() { QString filter; filter = "JPEG p_w_picpath 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(); } |
程序運行結果:
類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
……
具體的代碼實現:
private slots: //響應鼠標移動的消息,實時輸出鼠標的當前位置 void updateCoords(vtkObject* obj);
private: vtkEventQtSlotConnect* m_Connections; |
源文件:
//構造函數裏: m_Connections = vtkEventQtSlotConnect::New(); m_Connections->Connect(m_QVTKWidget->GetRenderWindow()->GetInteractor(), vtkCommand::MouseMoveEvent, this, SLOT(updateCoords(vtkObject*)));
//槽函數的實現 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); } |
程序運行結果:
示例代碼及該博文文檔下載地址:http://download.csdn.net/detail/www_doling_net/5137375