【转】VTK与Qt整合的示例
?VTK與Qt整合的示例
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腳本的注釋,結合這個圖以及腳本的注釋,相信你應該能明白了。
?
| #---------------------------------------------- # 下面這兩行,沒什么好解釋的 cmake_minimum_required( VERSION 2.8 ) project( YourProjectName ) ? #---------------------------------------------- # 下面這兩行,也沒什么好解釋的 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} ) |
1.2 用CMake來管理Qt與VTK工程
我們在上面的基礎上添加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注釋的不太像之外,其他的都一樣,不再解釋。
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最后添加):
| #----------------------------------------------------------------------------------- # 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() |
?
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兩個腳本文件。如果你要編譯、運行Debug版本的工程,即雙擊StartVS_debug.bat文件打開對應的工程,同理,Release版本的也一樣。一旦按這種方式打開相應的工程,就不用再擔心類似“無法加載***.dll文件”的錯誤了。如果你的程序還增加了ITK等函數庫,也可以照著上面的腳本作相應的修改。
注意:使用時將CreateWindowsBatchScript.cmake和StartVS.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:
| #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(); } |
?
程序運行結果:
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
……
具體的代碼實現:
| 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
?
本文來源:?http://blog.csdn.net/www_doling_net/article/details/8668870
轉載于:https://blog.51cto.com/2845385/1157522
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的【转】VTK与Qt整合的示例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 离谱!女子车内染上HPV 车险公司被判赔
- 下一篇: 【转】医学图像中的窗宽、窗位!!