锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

VTK:交互与Widget——观察者/命令模式

时间:2022-10-28 18:00:00 rwi电阻br4x121rok

1.绪论

强大的可视化系统不仅需要强大的数据处理能力,还需要方便易用的交互功能。图形处理软件ParaView、
德国癌症研究中心开发的MITK开源软件系统提供了强大的交互功能。VTK除了监控鼠标、
键盘等外部设备的新闻外,交互功能还可以在渲染场景中生成不同功能的交互部件(Widget),用于控制可视化过程的参数,以满足用户的渲染要求。

2.观察者/命令模式

1.观察者/命令者是VTK设计模式较多。VTK绝大多数类都是从衍生出来的vtkObject。查看类vtkObject可以找到接口AddObserve()、RemoveObserve()、GetCommand()等函数。
2.观察者/命令模式是指一个Object可以有多个Observe,他定义了对象之间的一对多依赖关系,作为一个对象Object当对象的状态发生变化时,一切都取决于它Observe对象被通知并自动更新。命令模式属于对象行为模式他将请求封装为对象,并提供一致的接口发送请求,当事件发生时,他没有直接将事件传递给事件调用人,而是在命令和调用人之间增加了一个中间人,切断了这种直接关系,并将两者隔离开来。事件调用人只处理接口,不与具体事件互动。
在VTK观察者/命令模式可以通过两种方式实现,分别使用时间回调函数从VTKCommand具体子类的衍生

  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对象中。当该对象发生观察者感兴趣的事件时,就会自动调用回调函数,执行相关操作。

  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); //很重要! 
  1. 将VTKCallbackCommand将对象添加到对象的观察者列表中。
//Step2:将vtkCallbackCommand将对象添加到观察者列表中。 rwi->SetRenderWindow(viewer->GetRenderWindow()); //唤醒显示窗口 rwi->AddObserver(vtkCommand::LeftButtonPressEvent, mouseCallback); 
#include "Test.h"
#include 
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);

#include 

long cntPress = 0;
void MyCallbackFunc(vtkObject*, unsigned long eid, void* clientdata, void* calldata)
{ 
        
	std::cout << "You have clicked : " << ++cntPress << " times" << std::endl;
}


#include 
#include 
#include 
#include 
#include 
#include 

int main()
{ 
        
	vtkSmartPointer<vtkJPEGReader> reader =
		vtkSmartPointer<vtkJPEGReader>::New();
	reader->SetFileName("data/lena.jpg");
	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;
}

在这里插入图片描述VTK中的vtkRenderWindowInteractor提供了一种独立于平台的交互机制,用来响应不同平台的鼠标、按键和时钟等消息。当渲染窗口中有事件发生时(比如说单机消息),vtkRenderWindowInteractor内部会调用与平台相关的子类,将该消息转换成对应平台的消息。因此,该例的核心在于:通过vtkRenderWindowInteractor来监听鼠标左键的消息,一旦监听到对象的观察者列表中的消息时,程序会自动调用事件回调函数。

2.2 vtkCommand子类
观察者/命令模式除了使用事件回调函数外,还可以直接从vtkCommand类中派生出子类来实现

#include 
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

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函数中。
锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章