VTK修炼之道71:交互与Widget_观察者/命令模式
生活随笔
收集整理的這篇文章主要介紹了
VTK修炼之道71:交互与Widget_观察者/命令模式
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1.前言
一個強大的可視化系統不僅需要強大的數據處理能力,也需要方便易用的交互功能。圖形處理軟件ParaView(hhttp://www.paraview.org)、德國癌癥研究中心研發的MITK(http://www.mitk.org)等開源軟件系統都提供了強大的交互功能,作為ParaView、MITK等軟件構件基礎的VTK同樣也提供了各種各樣的交互功能。 VTK的交互除了可以監聽來自鼠標、鍵盤等外部設備的消息,還可以在渲染場景中生成功能各異的交互部件(Widget),用于控制可視化過程的參數,達到用戶的渲染要求。2.觀察者/命令模式(Observe/Command)
觀察者/命令模式是VTK里用的比較多的設計模式。 VTK中絕大多數的類都派生自vtkObject。查看類vtkObject的接口可以找到AddObserve()、RemoveObserve()、GetCommand()等函數。 觀察者/命令模式是指一個Object可以有多個Observe,他定義了對象間的一種“一對多”的依賴關系,當一個Object對象的狀態發生改變時,所有依賴于它的Observe對象都得到通知而被自動更新。命令模式屬于對象行為模式,他將一個請求封裝為一個對象,并提供一致性發送請求的接口,當一個事件發生時,他不直接把事件傳遞給事件調用者,而是在命令和調用者之間增加一個中間者,講這種直接關系切斷,同時將兩者都隔離。事件調用者只是和接口打交道,不和具體事件實現交互。 在VTK中,可以通過兩種方式來實現觀察者/命令模式,他們分別是使用時間回調函數、從VTKCommand派生出具體的子類。2.1 觀察者-事件回調方案
在vtkObject中,有如下函數:unsigned long AddObserver(unsigned long event, vtkCommand *, float priority = 0.0f); unsigned long AddObserver(const char* event, vtkCommand *, float priority = 0.0f);AddObserver()函數的作用就是針對某個事件添加掛插著到某個VTK對象中。 當該對象發生觀察者感興趣的事件時,就會自動調用回調函數,執行相關操作。 下面是一個非常簡單的例子演示了在VTK里是如何使用“觀察者-事件回調函數”方案的: #include <vtkAutoInit.h> VTK_MODULE_INIT(vtkRenderingOpenGL); VTK_MODULE_INIT(vtkInteractionStyle);#include <vtkCallbackCommand.h>long cntPress = 0; void MyCallbackFunc(vtkObject*, unsigned long eid, void* clientdata, void* calldata) {std::cout << "You have clicked : " << ++cntPress << " times" << std::endl; }#include <vtkSmartPointer.h> #include <vtkPNGReader.h> #include <vtkImageViewer2.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h>int main() {vtkSmartPointer<vtkPNGReader> reader =vtkSmartPointer<vtkPNGReader>::New();reader->SetFileName("vtk.png");reader->Update();vtkSmartPointer<vtkImageViewer2> viewer =vtkSmartPointer<vtkImageViewer2>::New();viewer->SetInputData(reader->GetOutput());viewer->GetRenderer()->SetBackground(0, 0, 0);viewer->SetSize(480, 320);viewer->GetRenderWindow()->SetWindowName("Observer-Callback");vtkSmartPointer<vtkRenderWindowInteractor> rwi =vtkSmartPointer<vtkRenderWindowInteractor>::New();viewer->SetupInteractor(rwi);viewer->Render();/*************************************************************///Step1:設置事件回調函數vtkSmartPointer<vtkCallbackCommand> mouseCallback =vtkSmartPointer<vtkCallbackCommand>::New();mouseCallback->SetCallback(MyCallbackFunc); //很重要!!!//Step2:將vtkCallbackCommand對象添加到觀察者列表。rwi->SetRenderWindow(viewer->GetRenderWindow()); //喚醒顯示窗口rwi->AddObserver(vtkCommand::LeftButtonPressEvent, mouseCallback);rwi->Initialize();rwi->Start();return 0; }輸出結果: 通過上例,我們可以總結一下“觀察者-回調函數”交互方案主要可以分為以下三個步驟: 1.定義回調函數。 回調函數的函數簽名只能是以下形式: void long MyCallbackFunc(vtkObject* obj, unsigned long eid, void* clientdata, void* calldata); 其中, obj:是調用事件的對象(即調用AddObserver()函數的對象,對應于本例的rwi); eid:是所要監聽的事件ID,VTK中的事件定義在vtkCommand.h文件中; clientdata:是與VTKCallbackCommand實例相關的數據,簡單地說,是指回調函數里需要訪問主程序里面得數據時,由主程序向回調函數傳遞的數據。 calldata:是執行vtkObject::InvokeEvent()函數時,隨著回調函數發送得數據,比如說,當調用ProgressEvent事件時,會自動發送當前的進度值作為callback。 2.創建一個VTKCallbackCommand對象,并調用VTKCallbackCommand::SetCallback()函數設置所定義的回調函數。 //Step1:設置事件回調函數 vtkSmartPointer<vtkCallbackCommand> mouseCallback =vtkSmartPointer<vtkCallbackCommand>::New(); mouseCallback->SetCallback(MyCallbackFunc); //很重要!!!3.將VTKCallbackCommand對象添加到對象的觀察者列表中。//Step2:將vtkCallbackCommand對象添加到觀察者列表。 rwi->SetRenderWindow(viewer->GetRenderWindow()); //喚醒顯示窗口 rwi->AddObserver(vtkCommand::LeftButtonPressEvent, mouseCallback);注意: VTK中的vtkRenderWindowInteractor提供了一種獨立于平臺的交互機制,用來響應不同平臺的鼠標、按鍵和時鐘等消息。當渲染窗口中有事件發生時(比如說單機消息),vtkRenderWindowInteractor內部會調用與平臺相關的子類,將該消息轉換成對應平臺的消息。 因此,該例的核心在于:通過vtkRenderWindowInteractor來監聽鼠標左鍵的消息,一旦監聽到對象的觀察者列表中的消息時,程序會自動調用事件回調函數。
2.2 vtkCommand子類
觀察者/命令模式除了使用事件回調函數外,還可以直接從vtkCommand類中派生出子類來實現。 示例代碼如下: #include <vtkAutoInit.h> VTK_MODULE_INIT(vtkRenderingOpenGL); VTK_MODULE_INIT(vtkInteractionStyle);#include <vtkCommand.h> #include <vtkSmartPointer.h> #include <vtkConeSource.h> #include <vtkPolyDataMapper.h> #include <vtkActor.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> #include <vtkInteractorStyleTrackballCamera.h>class myCallback :public vtkCommand { public:static myCallback* New(){return new myCallback;}void SetObject(vtkConeSource* cone){m_cone = cone;}virtual void Execute(vtkObject* caller, unsigned long eventId, void* callData){std::cout << "LeftButton has been pressed: " << std::endl<< "The Height: " << m_cone->GetHeight() << std::endl<< "The Radius: " << m_cone->GetRadius() << std::endl;}private:vtkConeSource* m_cone; }; int main() {vtkSmartPointer<vtkConeSource> cone =vtkSmartPointer<vtkConeSource>::New();cone->SetHeight(10);cone->SetRadius(4);cone->Update();/*************************************************************/vtkSmartPointer<vtkPolyDataMapper> mapper =vtkSmartPointer<vtkPolyDataMapper>::New();mapper->SetInputConnection(cone->GetOutputPort());vtkSmartPointer<vtkActor> actor =vtkSmartPointer<vtkActor>::New();actor->SetMapper(mapper);vtkSmartPointer<vtkRenderer> render =vtkSmartPointer<vtkRenderer>::New();render->AddActor(actor);render->SetBackground(1, 1, 1);vtkSmartPointer<vtkRenderWindow> rw =vtkSmartPointer<vtkRenderWindow>::New();rw->AddRenderer(render);rw->SetWindowName("Interaction By SubCommand");rw->SetSize(320, 320);vtkSmartPointer<vtkRenderWindowInteractor> rwi =vtkSmartPointer<vtkRenderWindowInteractor>::New();rwi->SetRenderWindow(rw);vtkSmartPointer<vtkInteractorStyleTrackballCamera> style =vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();rwi->SetInteractorStyle(style);vtkSmartPointer<myCallback> callback =vtkSmartPointer<myCallback>::New();callback->SetObject(cone);rwi->AddObserver(vtkCommand::LeftButtonPressEvent, callback);rwi->Initialize();rwi->Start();return 0; }輸出結果為: 這個例子實現的功能也是監聽鼠標左鍵單機的消息。 基于“觀察者-vtkCommand子類”的實現方案也遵循三個步驟。 1. 從vtkCommand類中派生出子類,并實現vtkCommand::Execute()虛函數。 該函數原型為: virtual void Execute(vtkObject* caller, ?unsigned long eventId, ?void* callData )= 0; Execute()時純虛函數,所以,從vtkCommand派生類中都必須要實現這個方法。 2.實例化vtkCommand子類的對象,并調用相關的方法。 3.調用觀察者函數。 調用AddObserver()函數監聽感興趣的事件,如果所監聽的事件發生,就會調用vtkCommand子類中定義的Execute()函數。 因此,針對所監聽的事件,程序需要把實現的功能放在Execute函數中。3.參看資料
1.《C++ primer》2.《The VTK User’s Guide – 11thEdition》
3. ?張曉東, 羅火靈. VTK圖形圖像開發進階[M]. 機械工業出版社, 2015.
總結
以上是生活随笔為你收集整理的VTK修炼之道71:交互与Widget_观察者/命令模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【飞秋】网络的基础-域名篇
- 下一篇: 飞秋文件传输模拟实现代码