观察者/命令模式
vtk中用到大量的面向对象设计模式,如工厂模式、观察者/命令模式、另外还用到引用计数与智能指针等高级内存管理知识。
前面的博客讲过观察者/命令模式这个模式了 这里就不细说了。
观察者/命令模式(Observer/Command)是vtk里用的较多的设计模式。vtk中 绝大多数的类都派生自vtkobject。查看类vtkobject的接口可以找到AddObserver()、RemoveObserver()、GetCommand()等函数,从函数的字面意思可以看出,这些函数是与观察者/命令模式相关的。
观察者/命令模式是指一个Object可以有多个Observer,它定义了对象间的一种多对多的依赖关系,当一个Object对象的状态发生改变时,所有依赖于它的Observer对象都得到通知而被自动更新。命令模式属于对象的行为模式,它将一个请求封装为一个对象,并提供一致性发送请求的接口,当一个事件发生时,它不直接把事件传递给事件调用者,而是在命令和调用者之间增加一个中间者,讲这种关系直接切断,同时将两者都隔离。事件调用者只是和接口打交道,不和具体时间实现交互,在vtk中,可以通过这两种方式来实现观察者/命令模式,它们分别是使用事件回调函数以及从VTK派生出来具体的子类。
事件回调函数
在vtkOBject中,有如下函数:
unsigned long AddObserver(unsigned long event,vtkCommand *,float priority=0.0f);
unsigned long AddObserver(unsigned char* event,vtkCommand *,float priority=0.0f);
AddObserver()函数的作用就是针对某个事件添加观察者到某个VTK对象中,当该对象发生观察者感兴趣的事件时,就会调用回调函数,执行相关的操作。
#include <vtkSmartPointer.h>
#include <vtkImageReader2.h>
#include <vtkMatrix4x4.h>
#include <vtkImageReslice.h>
#include <vtkLookupTable.h>
#include <vtkImageMapToColors.h>
#include <vtkImageActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkCommand.h>
#include <vtkImageData.h>
#include <vtkMetaImageReader.h>
#include <vtkImageCast.h>
#include"vtkPNGReader.h"
#include"vtkAutoInit.h"
#include"vtkImageViewer2.h"
#include"vtkProperty.h"
#include"vtkCallbackCommand.h"
VTK_MODULE_INIT(vtkRenderingOpenGL);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL);
long pressCounts = 0;
void MyCallbackFunc(vtkObject *,unsigned long eid,void *clientdata,void *calldata)
{
std::cout << "You have clicked: " << ++pressCounts << " Times." << endl;
}
int main(int argc,char *argv[])
{
std::string filename = "VTK-logo.png";
vtkSmartPointer<vtkPNGReader> reader = vtkSmartPointer<vtkPNGReader>::New();
reader->SetFileName(filename.c_str());
vtkSmartPointer<vtkImageViewer2> viewer = vtkSmartPointer<vtkImageViewer2>::New();
viewer->SetInputData(reader->GetOutput());
vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
viewer->SetupInteractor(interactor);
viewer->Render();
vtkSmartPointer<vtkCallbackCommand> mouseCallback = vtkSmartPointer<vtkCallbackCommand>::New();
mouseCallback->SetCallback(MyCallbackFunc);
interactor->SetRenderWindow(viewer->GetRenderWindow());
interactor->AddObserver(vtkCommand::LeftButtonPressEvent,mouseCallback);
interactor->Initialize();
interactor->Start();
return 0;
}
vtkCommand子类
观察者/命令模式除了使用事件回调函数外,还可以直接从vtkCommand类中派生出子类来实现。
#include <vtkSmartPointer.h>
#include <vtkImageReader2.h>
#include <vtkMatrix4x4.h>
#include <vtkImageReslice.h>
#include <vtkLookupTable.h>
#include <vtkImageMapToColors.h>
#include <vtkImageActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkCommand.h>
#include <vtkImageData.h>
#include <vtkMetaImageReader.h>
#include <vtkImageCast.h>
#include"vtkPNGReader.h"
#include"vtkAutoInit.h"
#include"vtkImageViewer2.h"
#include"vtkProperty.h"
#include"vtkCallbackCommand.h"
#include"vtkPolyDataMapper.h"
VTK_MODULE_INIT(vtkRenderingOpenGL);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL);
#include"vtkConeSource.h"
class vtkMyCallback : public vtkCommand
{
public:
static vtkMyCallback *New()
{
return new vtkMyCallback;
}
void SetObject(vtkConeSource *cone)
{
m_Cone = cone;
}
virtual void Execute(vtkObject *caller,unsigned long eventId,void *callData)
{
std::cout << "Left button pressed.\n"
<< "The Height:" << m_Cone->GetHeight() << "\n"
<< "The Radius:" << m_Cone->GetRadius() << std::endl;
}
private:
vtkConeSource *m_Cone;
};
int main()
{
vtkSmartPointer<vtkConeSource> cone = vtkSmartPointer<vtkConeSource>::New();
cone->SetHeight(3.0);
cone->SetRadius(1.0);
cone->SetResolution(1.0);
vtkSmartPointer<vtkPolyDataMapper> coneMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
coneMapper->SetInputConnection(cone->GetOutputPort());
vtkSmartPointer<vtkActor> coneActor = vtkSmartPointer<vtkActor>::New();
coneActor->SetMapper(coneMapper);
vtkSmartPointer<vtkRenderer> ren1 = vtkSmartPointer<vtkRenderer>::New();
ren1->AddActor(coneActor);
ren1->SetBackground(0.1,0.2,0.4);
vtkSmartPointer<vtkRenderWindow> renwin = vtkSmartPointer<vtkRenderWindow>::New();
renwin->AddRenderer(ren1);
renwin->SetSize(300, 300);
vtkSmartPointer<vtkRenderWindowInteractor> iren = vtkSmartPointer<vtkRenderWindowInteractor>::New();
iren->SetRenderWindow(renwin);
vtkSmartPointer<vtkInteractorStyleTrackballCamera> style = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
iren->SetInteractorStyle(style);
vtkSmartPointer<vtkMyCallback> callback = vtkSmartPointer<vtkMyCallback>::New();
callback->SetObject(cone);
iren->AddObserver(vtkCommand::LeftButtonPressEvent,callback);
iren->Initialize();
iren->Start();
return EXIT_SUCCESS;
}
上面的程序同样演示的是鼠标左键单击消息,如果监听到单击消息,就在控制台中打出主程序所设置的椎体的高和底面积等信息。vtkMyCallback是从vtkCommand类中派生的,SetObject()函数用于设置椎体对象。利用这种方式使用VTK的观察者/命令模式也应该遵循如下三个步骤。
**(1) 从vtkCommand类派生子类,并实现vtkCommand::Execute()虚函数,该函数的原型为:
**virtual void Execute(vtkObject *caller,unsigned long evemtId,void *callData)=0;
(3) 调用AddObserver()函数监听感兴趣的事件。如果所监听的事件会发生,会调用vtkCommand子类中的Execute()函数,针对所监听的事件,程序需要实现的功能一般都放在Execute()函数中。