vtkObject类

vtkObject类是VTK中大多数类的基类;
        vtkObject类提供了很多API用于跟踪对象修改时间,debug消息,打印类堆栈,以及事件回调;
        vtkObject类和它众多派生类构成了VTK框架;
        少数例外情况往往是非常小的帮助器类,它们通常永远不会被实例化,或者是在多重继承妨碍的情况下。
        vtkObject还执行引用计数:引用计数的对象存在,只要其他对象使用它们。
         一旦删除对引用计数对象的最后一个引用,该对象将自动销毁。]
        注意:1.VTK中的对象应该使用New和Delete申请和释放;
                   2.VTK对象不会被分配在栈空间内,是因为构造函数被设置为protected方法;

#ifndef vtkObject_h
#define vtkObject_h#include "vtkCommonCoreModule.h" // For export macro
#include "vtkObjectBase.h"
#include "vtkSetGet.h"
#include "vtkTimeStamp.h"
#include "vtkWeakPointerBase.h" // needed for vtkWeakPointerclass vtkSubjectHelper;
class vtkCommand;class VTKCOMMONCORE_EXPORT vtkObject : public vtkObjectBase
{
public:vtkBaseTypeMacro(vtkObject, vtkObjectBase);// 创建一个对象,关闭Debug标识;// 时间戳初始为0,启用引用计数static vtkObject* New();#ifdef _WIN32// avoid dll boundary problemsvoid* operator new(size_t tSize);void operator delete(void* p);
#endif// Turn debugging output on.virtual void DebugOn();// Turn debugging output off.virtual void DebugOff();// Get the value of the debug flag.bool GetDebug();// Set the value of the debug flag. A true value turns debugging on.void SetDebug(bool debugFlag);// 执行vtkErrorMacro时调用此方法。它允许调试器在出错时中断。static void BreakOnError();// 更新对象的时间戳--修改时间;// 许多过滤器依靠修改时间来确定是否需要重新计算数据。// 修改时间是唯一的单调递增无符号长整数。virtual void Modified();// 返回对象的修改次数virtual vtkMTimeType GetMTime();// print调用的方法,用于打印有关对象(包括超类)的信息。// 通常不由用户调用(改为使用Print()),而是在分层打印过程中用于组合多个类的输出。void PrintSelf(ostream& os, vtkIndent indent) override;// 这是一个全局标志,用于控制是否显示任何调试、警告或错误消息。static void SetGlobalWarningDisplay(int val);static void GlobalWarningDisplayOn() { vtkObject::SetGlobalWarningDisplay(1); }static void GlobalWarningDisplayOff() { vtkObject::SetGlobalWarningDisplay(0); }static int GetGlobalWarningDisplay();// 允许用户对任意的VTK对象添加、删除以及调用观察者的回调函数;// 是观察者模式的实例;// 当需要通过指定要响应的事件和要执行的vtkCommand时,可以添加一个观察者。// 它返回一个unsigned long的tag,可在以后用于删除event或检索command。// 在调用events时,将按照events添加的顺序调用观察者。// 如果指定了优先级值,则优先级高的commands先被调用。// 一个command可以设置一个跳出abort标识flag,用于停止event的执行;unsigned long AddObserver(unsigned long event, vtkCommand*, float priority = 0.0f);unsigned long AddObserver(const char* event, vtkCommand*, float priority = 0.0f);vtkCommand* GetCommand(unsigned long tag);void RemoveObserver(vtkCommand*);void RemoveObservers(unsigned long event, vtkCommand*);void RemoveObservers(const char* event, vtkCommand*);vtkTypeBool HasObserver(unsigned long event, vtkCommand*);vtkTypeBool HasObserver(const char* event, vtkCommand*);void RemoveObserver(unsigned long tag);void RemoveObservers(unsigned long event);void RemoveObservers(const char* event);void RemoveAllObservers(); // remove every last one of themvtkTypeBool HasObserver(unsigned long event);vtkTypeBool HasObserver(const char* event);// AddObserver的重载,允许开发人员添加类成员函数作为事件的回调。// 回调函数有两种类型://    1. void foo(void);//    2. void foo(vtkObject*, unsigned long, void*);// 如果回调函数是vtkObjectBase派生对象的成员函数,那么如果对象被析构,回调将自动禁用(但观察者不会自动删除)。// 如果回调函数是任何其他类型对象的成员,则必须在对象销毁之前删除观察者,否则下次事件发生时将使用其死指针。// 这些函数的典型用法如下://    SomeClassOfMine* observer = SomeClassOfMine::New();//    to_observe->AddObserver(event, observer, &SomeClassOfMine::SomeMethod);// 返回值是一个tag,可以根据tag删除观察者。// 请注意,这不会影响vtkObjectBase派生的观察者的参考计数,在观察者仍在原位的情况下,可以安全地删除这些参考计数。// 对于非vtkObjectBase观察者,在移除观察者之前,不应删除该观察者。template <class U, class T>unsigned long AddObserver(unsigned long event, U observer, void (T::*callback)(), float priority = 0.0f){vtkClassMemberCallback<T>* callable = new vtkClassMemberCallback<T>(observer, callback);// 当观察者被清理后,callable也将被删除(look at vtkObjectCommandInternal)return this->AddTemplatedObserver(event, callable, priority);}template <class U, class T>unsigned long AddObserver(unsigned long event, U observer,void (T::*callback)(vtkObject*, unsigned long, void*), float priority = 0.0f){vtkClassMemberCallback<T>* callable = new vtkClassMemberCallback<T>(observer, callback);// 当观察者被清理后,callable也将被删除(look at vtkObjectCommandInternal)return this->AddTemplatedObserver(event, callable, priority);}// 允许用户使用回调方法的返回值设置AbortFlagOntemplate <class U, class T>unsigned long AddObserver(unsigned long event, U observer,bool (T::*callback)(vtkObject*, unsigned long, void*), float priority = 0.0f){vtkClassMemberCallback<T>* callable = new vtkClassMemberCallback<T>(observer, callback);// 当观察者被清理后,callable也将被删除(look at vtkObjectCommandInternal)return this->AddTemplatedObserver(event, callable, priority);}// 此方法调用一个事件,并返回该事件是否已被中止。// 如果事件被中止,则返回值为1,否则为0。int InvokeEvent(unsigned long event, void* callData);int InvokeEvent(const char* event, void* callData);int InvokeEvent(unsigned long event) { return this->InvokeEvent(event, nullptr); }int InvokeEvent(const char* event) { return this->InvokeEvent(event, nullptr); }protected:vtkObject();~vtkObject() override;void RegisterInternal(vtkObjectBase*, vtkTypeBool check) override;void UnRegisterInternal(vtkObjectBase*, vtkTypeBool check) override;bool Debug;                      // 开启debug消息开关vtkTimeStamp MTime;              // 跟踪对象的修改时间vtkSubjectHelper* SubjectHelper; // 观察者列表// 这些方法允许一个命令独占地获取所有事件。// 一旦事件序列开始,小部件通常会使用这种方法来获取事件。// 提供这些方法是为了支持vtkInteractorObserver类中的公共方法。// 请注意,这些方法旨在支持vtkInteractorObserver,因为它们使用两个单独的vtkCommand来监视鼠标和按键事件。void InternalGrabFocus(vtkCommand* mouseEvents, vtkCommand* keypressEvents = nullptr);void InternalReleaseFocus();private:vtkObject(const vtkObject&) = delete;void operator=(const vtkObject&) = delete;// 以下类(vtkClassMemberCallbackBase、// vtkClassMemberCallback和vtkClassMemberHanderPointer)// 以及vtkObjectCommandInternal用于支持模板化的AddObserver()重载,// 这些重载允许开发人员添加属于类成员函数的事件回调;class vtkClassMemberCallbackBase{public:// 回调函数,当事件发生时,被调用;virtual bool operator()(vtkObject*, unsigned long, void*) = 0;virtual ~vtkClassMemberCallbackBase() {}};// 这是vtkObjectBase的弱指针,是其他所有对象的常规空指针template <class T>class vtkClassMemberHandlerPointer{public:void operator=(vtkObjectBase* o){// The cast is needed in case "o" has multi-inheritance,// to offset the pointer to get the vtkObjectBase.if ((this->VoidPointer = dynamic_cast<T*>(o)) == nullptr) {// fallback to just using its vtkObjectBase as-is.this->VoidPointer = o;}this->WeakPointer = o;this->UseWeakPointer = true;}void operator=(void* o){this->VoidPointer = o;this->WeakPointer = nullptr;this->UseWeakPointer = false;}T* GetPointer(){if (this->UseWeakPointer && !this->WeakPointer.GetPointer()) {return nullptr;}return static_cast<T*>(this->VoidPointer);}private:vtkWeakPointerBase WeakPointer;void* VoidPointer;bool UseWeakPointer;};// 支持三种函数类型的回调函数:// void function();// void function(vtkObject*, unsigned long, void*);// bool function(vtkObject*, unsigned long, void*);template <class T>class vtkClassMemberCallback : public vtkClassMemberCallbackBase{vtkClassMemberHandlerPointer<T> Handler;void (T::*Method1)();void (T::*Method2)(vtkObject*, unsigned long, void*);bool (T::*Method3)(vtkObject*, unsigned long, void*);public:vtkClassMemberCallback(T* handler, void (T::*method)()){this->Handler = handler;this->Method1 = method;this->Method2 = nullptr;this->Method3 = nullptr;}vtkClassMemberCallback(T* handler, void (T::*method)(vtkObject*, unsigned long, void*)){this->Handler = handler;this->Method1 = nullptr;this->Method2 = method;this->Method3 = nullptr;}vtkClassMemberCallback(T* handler, bool (T::*method)(vtkObject*, unsigned long, void*)){this->Handler = handler;this->Method1 = nullptr;this->Method2 = nullptr;this->Method3 = method;}~vtkClassMemberCallback() override {}// 当event被调用时,被执行;bool operator()(vtkObject* caller, unsigned long event, void* calldata) override{T* handler = this->Handler.GetPointer();if (handler) {if (this->Method1) {(handler->*this->Method1)();}else if (this->Method2) {(handler->*this->Method2)(caller, event, calldata);}else if (this->Method3) {return (handler->*this->Method3)(caller, event, calldata);}}return false;}};// 由AddObserver的模板类型的变量调用unsigned long AddTemplatedObserver(unsigned long event, vtkClassMemberCallbackBase* callable, float priority);// vtkObjectCommandInternal类对象需要调用AddTemplatedObserver().friend class vtkObjectCommandInternal;
};#endif

vtkObserver类

vtkObserver类声明定义在vtkObject.cxx文件中;

// 命令与观察模式被用于调用和分发事件;
// vtkSubjectHelper类持有了一个观察者列表(列表中有实例化的vtkCommand对象)用于响应事件;
class vtkObserver
{
public:vtkObserver(): Command(nullptr), Event(0), Tag(0), Next(nullptr), Priority(0.0){}~vtkObserver(){this->Command->UnRegister(nullptr);}// 打印对象内的属性void PrintSelf(ostream& os, vtkIndent indent);// 与当前观察者关联的命令vtkCommand* Command;// 事件IDunsigned long Event;// Tag IDunsigned long Tag;// 下一个观察者指针,用于构成一个单链表vtkObserver* Next;// 优先级float Priority;
};

vtkCommand类

vtkCommand类是观察者/命令设计模式的实现。
        在这种设计模式中,任何vtkObject实例都可以被“观察”到它可能调用的任何事件。
        例如,vtkRenderer在开始渲染时调用 StartEvent,在完成渲染时调用 EndEvent。过滤器(vtkProcessObject 的子类)在过滤器处理数据时调用 StartEvent、ProgressEvent 和 EndEvent。
        使用vtkObject中的 AddObserver()方法添加事件的观察者。AddObserver()除了需要事件 id 或名称外,还需要一个vtkCommand实例(或子类)。注意vtkCommand旨在被子类化,以便可以打包支持回调所需的信息。

事件处理可以组织在优先级列表中,因此可以通过设置AbortFlag变量来截断特定事件的处理。使用AddObserver()方法设置优先级。默认情况下优先级为0,相同优先级的事件按后处理顺序处理。事件的排序或中止对于诸如3D小部件之类的事情很重要,如果选择了小部件,它们会处理一个事件(然后中止对该事件的进一步处理)。除此以外。该事件被传递以进行进一步处理。

当vtkObject的实例调用事件时,它还将一个可选的void指针传递给callData。这个callData大多数时候是nullptr。callData不是特定于事件类型,而是特定于调用特定事件的vtkObject类型。例如,vtkCommand::PickEvent由vtkProp调用,带有nullptr callData,但由vtkInteractorStyleImage调用,并带有指向vtkInteractorStyleImage对象本身的指针。

#ifndef vtkCommand_h
#define vtkCommand_h#include "vtkCommonCoreModule.h" // For export macro
#include "vtkObject.h"           // Need vtkTypeMacro
#include "vtkObjectBase.h"// clang-format off
// Define all types of events here.
// Using this macro makes it possible to avoid mismatches between the event
// enums and their string counterparts.
#define vtkAllEventsMacro()                                                                        \_vtk_add_event(AnyEvent)                                                                       \_vtk_add_event(DeleteEvent)                                                                    \_vtk_add_event(StartEvent)                                                                     \_vtk_add_event(EndEvent)                                                                       \_vtk_add_event(RenderEvent)                                                                    \_vtk_add_event(ProgressEvent)                                                                  \_vtk_add_event(PickEvent)                                                                      \_vtk_add_event(StartPickEvent)                                                                 \_vtk_add_event(EndPickEvent)                                                                   \_vtk_add_event(AbortCheckEvent)                                                                \_vtk_add_event(ExitEvent)                                                                      \_vtk_add_event(LeftButtonPressEvent)                                                           \_vtk_add_event(LeftButtonReleaseEvent)                                                         \_vtk_add_event(MiddleButtonPressEvent)                                                         \_vtk_add_event(MiddleButtonReleaseEvent)                                                       \_vtk_add_event(RightButtonPressEvent)                                                          \_vtk_add_event(RightButtonReleaseEvent)                                                        \_vtk_add_event(EnterEvent)                                                                     \_vtk_add_event(LeaveEvent)                                                                     \_vtk_add_event(KeyPressEvent)                                                                  \_vtk_add_event(KeyReleaseEvent)                                                                \_vtk_add_event(CharEvent)                                                                      \_vtk_add_event(ExposeEvent)                                                                    \_vtk_add_event(ConfigureEvent)                                                                 \_vtk_add_event(TimerEvent)                                                                     \_vtk_add_event(MouseMoveEvent)                                                                 \_vtk_add_event(MouseWheelForwardEvent)                                                         \_vtk_add_event(MouseWheelBackwardEvent)                                                        \_vtk_add_event(ActiveCameraEvent)                                                              \_vtk_add_event(CreateCameraEvent)                                                              \_vtk_add_event(ResetCameraEvent)                                                               \_vtk_add_event(ResetCameraClippingRangeEvent)                                                  \_vtk_add_event(ModifiedEvent)                                                                  \_vtk_add_event(WindowLevelEvent)                                                               \_vtk_add_event(StartWindowLevelEvent)                                                          \_vtk_add_event(EndWindowLevelEvent)                                                            \_vtk_add_event(ResetWindowLevelEvent)                                                          \_vtk_add_event(SetOutputEvent)                                                                 \_vtk_add_event(ErrorEvent)                                                                     \_vtk_add_event(WarningEvent)                                                                   \_vtk_add_event(StartInteractionEvent)                                                          \_vtk_add_event(DropFilesEvent)                                                                 \_vtk_add_event(UpdateDropLocationEvent)                                                        \/*^ mainly used by vtkInteractorObservers*/                                                \_vtk_add_event(InteractionEvent)                                                               \_vtk_add_event(EndInteractionEvent)                                                            \_vtk_add_event(EnableEvent)                                                                    \_vtk_add_event(DisableEvent)                                                                   \_vtk_add_event(CreateTimerEvent)                                                               \_vtk_add_event(DestroyTimerEvent)                                                              \_vtk_add_event(PlacePointEvent)                                                                \_vtk_add_event(DeletePointEvent)                                                               \_vtk_add_event(PlaceWidgetEvent)                                                               \_vtk_add_event(CursorChangedEvent)                                                             \_vtk_add_event(ExecuteInformationEvent)                                                        \_vtk_add_event(RenderWindowMessageEvent)                                                       \_vtk_add_event(WrongTagEvent)                                                                  \_vtk_add_event(StartAnimationCueEvent)                                                         \_vtk_add_event(ResliceAxesChangedEvent)                                                        \/*^ used by vtkAnimationCue*/                                                              \_vtk_add_event(AnimationCueTickEvent)                                                          \_vtk_add_event(EndAnimationCueEvent)                                                           \_vtk_add_event(VolumeMapperRenderEndEvent)                                                     \_vtk_add_event(VolumeMapperRenderProgressEvent)                                                \_vtk_add_event(VolumeMapperRenderStartEvent)                                                   \_vtk_add_event(VolumeMapperComputeGradientsEndEvent)                                           \_vtk_add_event(VolumeMapperComputeGradientsProgressEvent)                                      \_vtk_add_event(VolumeMapperComputeGradientsStartEvent)                                         \_vtk_add_event(WidgetModifiedEvent)                                                            \_vtk_add_event(WidgetValueChangedEvent)                                                        \_vtk_add_event(WidgetActivateEvent)                                                            \_vtk_add_event(ConnectionCreatedEvent)                                                         \_vtk_add_event(ConnectionClosedEvent)                                                          \_vtk_add_event(DomainModifiedEvent)                                                            \_vtk_add_event(PropertyModifiedEvent)                                                          \_vtk_add_event(UpdateEvent)                                                                    \_vtk_add_event(RegisterEvent)                                                                  \_vtk_add_event(UnRegisterEvent)                                                                \_vtk_add_event(UpdateInformationEvent)                                                         \_vtk_add_event(AnnotationChangedEvent)                                                         \_vtk_add_event(SelectionChangedEvent)                                                          \_vtk_add_event(UpdatePropertyEvent)                                                            \_vtk_add_event(ViewProgressEvent)                                                              \_vtk_add_event(UpdateDataEvent)                                                                \_vtk_add_event(CurrentChangedEvent)                                                            \_vtk_add_event(ComputeVisiblePropBoundsEvent)                                                  \_vtk_add_event(TDxMotionEvent)                                                                 \/*^ 3D Connexion device event */                                                             \_vtk_add_event(TDxButtonPressEvent)                                                            \/*^ 3D Connexion device event */                                                             \_vtk_add_event(TDxButtonReleaseEvent)                                                          \/* 3D Connexion device event */                                                              \_vtk_add_event(HoverEvent)                                                                     \_vtk_add_event(LoadStateEvent)                                                                 \_vtk_add_event(SaveStateEvent)                                                                 \_vtk_add_event(StateChangedEvent)                                                              \_vtk_add_event(WindowMakeCurrentEvent)                                                         \_vtk_add_event(WindowIsCurrentEvent)                                                           \_vtk_add_event(WindowFrameEvent)                                                               \_vtk_add_event(HighlightEvent)                                                                 \_vtk_add_event(WindowSupportsOpenGLEvent)                                                      \_vtk_add_event(WindowIsDirectEvent)                                                            \_vtk_add_event(WindowStereoTypeChangedEvent)                                                   \_vtk_add_event(WindowResizeEvent)                                                              \_vtk_add_event(UncheckedPropertyModifiedEvent)                                                 \_vtk_add_event(UpdateShaderEvent)                                                              \_vtk_add_event(MessageEvent)                                                                   \_vtk_add_event(StartSwipeEvent)                                                                \_vtk_add_event(SwipeEvent)                                                                     \_vtk_add_event(EndSwipeEvent)                                                                  \_vtk_add_event(StartPinchEvent)                                                                \_vtk_add_event(PinchEvent)                                                                     \_vtk_add_event(EndPinchEvent)                                                                  \_vtk_add_event(StartRotateEvent)                                                               \_vtk_add_event(RotateEvent)                                                                    \_vtk_add_event(EndRotateEvent)                                                                 \_vtk_add_event(StartPanEvent)                                                                  \_vtk_add_event(PanEvent)                                                                       \_vtk_add_event(EndPanEvent)                                                                    \_vtk_add_event(TapEvent)                                                                       \_vtk_add_event(LongTapEvent)                                                                   \_vtk_add_event(FourthButtonPressEvent)                                                         \_vtk_add_event(FourthButtonReleaseEvent)                                                       \_vtk_add_event(FifthButtonPressEvent)                                                          \_vtk_add_event(FifthButtonReleaseEvent)                                                        \_vtk_add_event(Move3DEvent)                                                                    \_vtk_add_event(Button3DEvent)                                                                  \_vtk_add_event(TextEvent)                                                                      \_vtk_add_event(LeftButtonDoubleClickEvent)                                                     \_vtk_add_event(RightButtonDoubleClickEvent)
// clang-format on#define vtkEventDeclarationMacro(_enum_name)                                                       \enum _enum_name                                                                                  \{                                                                                                \NoEvent = 0,                                                                                   \vtkAllEventsMacro() UserEvent = 1000                                                           \}// 是所有的command类的基类
class VTKCOMMONCORE_EXPORT vtkCommand : public vtkObjectBase
{
public:vtkBaseTypeMacro(vtkCommand, vtkObjectBase);// 减少对象的引用计数,效果等同于Delete(),每次减少引用计数1;void UnRegister();void UnRegister(vtkObjectBase*) override { this->UnRegister(); }// 所有继承vtkCommand的派生类必须实现Execute;// 这其实是实际上执行回调函数工作的方法。// caller:调用事件的对象;// eventId:事件ID;// callData:传入回调函数的参数结构体;// 注意:vtkObject::InvokeEvent()接受两个参数:事件ID和传入回调函数的参数结构体;//     通常,调用数据callData是nullptr,但用户可以打包数据并以这种方式传递到回调函数中。//     或者,可以使用派生的命令类来传递数据。virtual void Execute(vtkObject* caller, unsigned long eventId, void* callData) = 0;// 在事件名称和事件ID之间转换的方便方法。static const char* GetStringFromEventId(unsigned long event);static unsigned long GetEventIdFromString(const char* event);// 判断event类型事件中是否包含vtkEventDatastatic bool EventHasData(unsigned long event);// 设置/获取中止标志。// 如果设置为true,则不会执行其他命令。void SetAbortFlag(int f) { this->AbortFlag = f; }int GetAbortFlag() { return this->AbortFlag; }void AbortFlagOn() { this->SetAbortFlag(1); }void AbortFlagOff() { this->SetAbortFlag(0); }// 设置/获取被动观察者标志。// 如果标志被设置为true,则表示此command不会以任何方式更改系统的状态。(真.被动也)// 被动观察者首先被处理,即使另一个命令有焦点,也不会被调用。void SetPassiveObserver(int f) { this->PassiveObserver = f; }int GetPassiveObserver() { return this->PassiveObserver; }void PassiveObserverOn() { this->SetPassiveObserver(1); }void PassiveObserverOff() { this->SetPassiveObserver(0); }// 定义了一个Event事件的枚举// 用户定义的事件类型从vtkCommand::UserEvent开始,UserEvent+int表示自己的事件ID;// vtkAllEventsMacro中使用_vtk_add_event增加新事件;
#define _vtk_add_event(Enum) Enum,vtkEventDeclarationMacro(EventIds);
#undef _vtk_add_eventprotected:// 中断类型int AbortFlag;// 被动观察者标识int PassiveObserver;vtkCommand();~vtkCommand() override {}friend class vtkSubjectHelper;vtkCommand(const vtkCommand& c) : vtkObjectBase(c) {}void operator=(const vtkCommand&) {}
};#endif /* vtkCommand_h */
#include "vtkCommand.h"
#include "vtkDebugLeaks.h"#ifdef VTK_DEBUG_LEAKS
static const char* leakname = "vtkCommand or subclass";
#endifvtkCommand::vtkCommand(): AbortFlag(0), PassiveObserver(0)
{
#ifdef VTK_DEBUG_LEAKSvtkDebugLeaks::ConstructClass(leakname);
#endif
}void vtkCommand::UnRegister()
{int refcount = this->GetReferenceCount() - 1;this->SetReferenceCount(refcount);if (refcount <= 0) {
#ifdef VTK_DEBUG_LEAKSvtkDebugLeaks::DestructClass(leakname);
#endifdelete this;}
}const char* vtkCommand::GetStringFromEventId(unsigned long event)
{switch (event)  {
#define _vtk_add_event(Enum)                                                                       \case Enum:                                                                                       \return #Enum;vtkAllEventsMacro()#undef _vtk_add_eventcase UserEvent : return "UserEvent";case NoEvent:return "NoEvent";}// Unknown event. return "NoEvent";
}unsigned long vtkCommand::GetEventIdFromString(const char* event)
{if (event) {#define _vtk_add_event(Enum)                                                                       \if (strcmp(event, #Enum) == 0)                                                                   \{                                                                                                \return Enum;                                                                                   \}vtkAllEventsMacro()#undef _vtk_add_eventif (strcmp("UserEvent",event) == 0) {return vtkCommand::UserEvent;}}return vtkCommand::NoEvent;
}bool vtkCommand::EventHasData(unsigned long event)
{switch (event) {// 只有两个事件Button3DEvent和Move3DEvent事件才有Data;case vtkCommand::Button3DEvent:case vtkCommand::Move3DEvent:return true;default:return false;}
}

vtkSubjectHelper类

vtkSubjectHelper类,是vtkObject的内部类,它保存了一个观察者(observers)列表,并向他们分发事件,还会调用与观察者关联的vtkCommand。

vtkSubjectHelper类位于vtkObject.cxx文件中;

vtkSubjectHelper类的声明:

// vtkSubjectHelper类,是vtkObject的内部类,它保存了一个观察者(observers)列表,并向他们分发事件,还会调用与观察者关联的vtkCommand。
class vtkSubjectHelper
{
public:vtkSubjectHelper(): ListModified(0), Focus1(nullptr), Focus2(nullptr), Start(nullptr), Count(1){}// 重置成员变量,释放观察者列表内存空间;~vtkSubjectHelper();// 增加观察者unsigned long AddObserver(unsigned long event, vtkCommand* cmd, float p);// 根据tag,从列表中删除一些观察者void RemoveObserver(unsigned long tag);// 根据事件id,从列表中删除一些观察者void RemoveObservers(unsigned long event);// 根据事件id和命令,从列表中删除一些观察者void RemoveObservers(unsigned long event, vtkCommand* cmd);// 删除列表中所有观察者void RemoveAllObservers();// 调用一个Event对应的Command;int InvokeEvent(unsigned long event, void* callData, vtkObject* self);// 根据tag,从列表中获取对应的命令信息vtkCommand* GetCommand(unsigned long tag);unsigned long GetTag(vtkCommand*);// 判断观察者列表中是否含有相同的eventvtkTypeBool HasObserver(unsigned long event);// 判断观察者列表中是否含有相同的event和vtkCommand的记录vtkTypeBool HasObserver(unsigned long event, vtkCommand* cmd);void GrabFocus(vtkCommand* c1, vtkCommand* c2){this->Focus1 = c1;this->Focus2 = c2;}void ReleaseFocus(){this->Focus1 = nullptr;this->Focus2 = nullptr;}// 打印成员属性void PrintSelf(ostream& os, vtkIndent indent);// 列表改动状态int ListModified;// This is to support the GrabFocus() methods found in vtkInteractorObserver.vtkCommand* Focus1;vtkCommand* Focus2;protected:vtkObserver* Start;// 用于tag的生成,只用于单调递增,不是Start列表中元素个数;unsigned long Count;
};

vtkSubjectHelper类的实现:

vtkSubjectHelper::~vtkSubjectHelper()
{vtkObserver* elem = this->Start;vtkObserver* next;while (elem){next = elem->Next;delete elem;elem = next;}this->Start = nullptr;this->Focus1 = nullptr;this->Focus2 = nullptr;
}unsigned long vtkSubjectHelper::AddObserver(unsigned long event, vtkCommand* cmd, float p)
{vtkObserver* elem;// initialize the new observer element// 初始化一个新的观察者节点elem = new vtkObserver;elem->Priority = p;elem->Next = nullptr;elem->Event = event;elem->Command = cmd;cmd->Register(nullptr);// Tag是列表的元素个数elem->Tag = this->Count;this->Count++;// now insert into the list// if no other elements in the list then this is Start// 将elem插入到列表中// 如果列表为空,那么elem就是Start,即单链表的首指针if (!this->Start) {this->Start = elem;}else {// insert high priority firstvtkObserver* prev = nullptr;vtkObserver* pos = this->Start;// 列表中根据vtkObserver的优先级排序,前面是高优先级,后面是低优先级;// 先找到比elem优先级低的节点位置prev,此时prev的优先级大于等于elem,pos优先级小于elem;// 如果没有找到prev位置,那么pos的优先级会高于elem的优先级while (pos->Priority >= elem->Priority && pos->Next) {prev = pos;pos = pos->Next;}// pos is Start and elem should not be start// 如果列表中只有一个节点,或者是链表中所有节点的优先级都大于elem,则elem放到链尾即可;if (pos->Priority > elem->Priority) {pos->Next = elem;}else {// 如果prev不为空,此时prev应该是中间节点了,这里就是一个单链表插入的步骤了;if (prev) {prev->Next = elem;}elem->Next = pos;// check to see if the new element is the start// 如果elem的优先级比链表首指针还大,那么就是一个头插法;// 将Start设置为elem;if (pos == this->Start) {this->Start = elem;}}}return elem->Tag;
}void vtkSubjectHelper::RemoveObserver(unsigned long tag)
{vtkObserver* elem;vtkObserver* prev;vtkObserver* next;elem = this->Start;prev = nullptr;// 遍历观察者列表,将Tag等于tag的节点全部删除while (elem) {if (elem->Tag == tag) {if (prev) {prev->Next = elem->Next;next = prev->Next;}else {this->Start = elem->Next;next = this->Start;}delete elem;elem = next;}else {prev = elem;elem = elem->Next;}}// 更改链表的修改标识:true;this->ListModified = 1;
}void vtkSubjectHelper::RemoveObservers(unsigned long event)
{vtkObserver* elem;vtkObserver* prev;vtkObserver* next;elem = this->Start;prev = nullptr;while (elem) {// 遍历观察者列表,将节点内Event等于event的节点全部删除if (elem->Event == event){if (prev) {prev->Next = elem->Next;next = prev->Next;}else {this->Start = elem->Next;next = this->Start;}delete elem;elem = next;}else {prev = elem;elem = elem->Next;}}// 更改链表的修改标识:true;this->ListModified = 1;
}void vtkSubjectHelper::RemoveObservers(unsigned long event, vtkCommand* cmd)
{vtkObserver* elem;vtkObserver* prev;vtkObserver* next;elem = this->Start;prev = nullptr;while (elem) {// 遍历观察者列表,将节点内Event等于event且Command等于cmd的节点全部删除if (elem->Event == event && elem->Command == cmd) {if (prev) {prev->Next = elem->Next;next = prev->Next;}else {this->Start = elem->Next;next = this->Start;}delete elem;elem = next;}else {prev = elem;elem = elem->Next;}}// 更改链表的修改标识:true;this->ListModified = 1;
}void vtkSubjectHelper::RemoveAllObservers()
{vtkObserver* elem = this->Start;vtkObserver* next;while (elem) {next = elem->Next;delete elem;elem = next;}this->Start = nullptr;
}vtkTypeBool vtkSubjectHelper::HasObserver(unsigned long event)
{vtkObserver* elem = this->Start;while (elem) {if (elem->Event == event || elem->Event == vtkCommand::AnyEvent) {return 1;}elem = elem->Next;}return 0;
}vtkTypeBool vtkSubjectHelper::HasObserver(unsigned long event, vtkCommand* cmd)
{vtkObserver* elem = this->Start;while (elem) {if ((elem->Event == event || elem->Event == vtkCommand::AnyEvent) && elem->Command == cmd) {return 1;}elem = elem->Next;}return 0;
}int vtkSubjectHelper::InvokeEvent(unsigned long event, void* callData, vtkObject* self)
{int focusHandled = 0;// 当我们调用事件时,观察者可以添加或删除观察者。// 为了确保观察者的迭代顺利进行,我们使用ListModified标识捕捉列表的任何更改。// 然而,观察者也可能会做一些事情,导致在这个对象中调用另一个事件。// 这意味着这个方法将被递归调用,这意味着我们将删除第一个调用所依赖的ListModified标志。// 要解决这个问题,请在栈上保存上一个ListModified值,然后在离开前将其还原。int saveListModified = this->ListModified;this->ListModified = 0;// 我们还需要保存在堆栈上调用的观察器(以免在事件调用中被重写)。// 还要确保我们不会调用(在另一个观察者调用期间添加的)任何新观察者。typedef std::vector<unsigned long> VisitedListType;VisitedListType visited;vtkObserver* elem = this->Start;// 如果找到了tag大于maxTag的element,这意味着它是在调用InvokeEvent后添加的(作为调用element command的副作用)。// 在这种情况下,该element将被丢弃而不执行。const unsigned long maxTag = this->Count;// 循环两三次,优先选择被动观察者和焦点持有者(如果有的话)。// 0.被动观察者循环//    循环所有观察者并执行那些被动观察者。//    这些观察者不应以任何方式影响系统的状态,也不应被允许中止事件。// 1.焦点循环//    如果有焦点持有者,循环所有观察者并执行与任一焦点持有者相关的。//    将焦点设置为表明焦点持有者处理了事件。// 2.剩余循环//    如果没有焦点持有者已经处理了该事件,则绕过其余的观察者。//    当没有焦点保持器时,该循环将始终执行。// 0.被动观察者循环// 被动观察者首先被处理,即使另一个命令有焦点,也不会被调用。vtkObserver* next;while (elem) {// 存储下一个指针,因为elem可能会因Command而消失next = elem->Next;// 获取Command的Passive标识;if (elem->Command->GetPassiveObserver() && (elem->Event == event || elem->Event == vtkCommand::AnyEvent) && elem->Tag < maxTag) {// lower_bound返回有序序列中可以插入的位置VisitedListType::iterator vIter = std::lower_bound(visited.begin(), visited.end(), elem->Tag);if (vIter == visited.end() || *vIter != elem->Tag) {// 按标签排序插入,以有限的插入成本加快未来的搜索,因为它重用了已经在正确位置的搜索迭代器visited.insert(vIter, elem->Tag);vtkCommand* command = elem->Command;command->Register(command);elem->Command->Execute(self, event, callData);command->UnRegister();}}if (this->ListModified) {vtkGenericWarningMacro(<< "Passive observer should not call AddObserver or RemoveObserver in callback.");elem = this->Start;this->ListModified = 0;}else {elem = next;}}// 1.焦点循环if (this->Focus1 || this->Focus2) {elem = this->Start;while (elem) {// 存储下一个指针,因为elem可能会因Command而消失next = elem->Next;if (((this->Focus1 == elem->Command) || (this->Focus2 == elem->Command))&& (elem->Event == event || elem->Event == vtkCommand::AnyEvent) && elem->Tag < maxTag){VisitedListType::iterator vIter =std::lower_bound(visited.begin(), visited.end(), elem->Tag);if (vIter == visited.end() || *vIter != elem->Tag) {// 不执行remainder loopfocusHandled = 1;// 按标签排序插入,以有限的插入成本加快未来的搜索,因为它重用了已经在正确位置的搜索迭代器visited.insert(vIter, elem->Tag);vtkCommand* command = elem->Command;command->Register(command);command->SetAbortFlag(0);elem->Command->Execute(self, event, callData);// if the command set the abort flag, then stop firing events and return// 如果命令设置了中止标志,则停止触发事件并返回if (command->GetAbortFlag()) {command->UnRegister();this->ListModified = saveListModified;return 1;}command->UnRegister();}}if (this->ListModified) {elem = this->Start;this->ListModified = 0;}else {elem = next;}}}// 2.剩余循环if (!focusHandled) {elem = this->Start;while (elem) {// store the next pointer because elem could disappear due to Commandnext = elem->Next;if ((elem->Event == event || elem->Event == vtkCommand::AnyEvent) && elem->Tag < maxTag) {VisitedListType::iterator vIter = std::lower_bound(visited.begin(), visited.end(), elem->Tag);if (vIter == visited.end() || *vIter != elem->Tag) {// Sorted insertion by tag to speed-up future searches at limited// insertion cost because it reuses the search iterator already at the// correct locationvisited.insert(vIter, elem->Tag);vtkCommand* command = elem->Command;command->Register(command);command->SetAbortFlag(0);elem->Command->Execute(self, event, callData);// if the command set the abort flag, then stop firing events and returnif (command->GetAbortFlag()) {command->UnRegister();this->ListModified = saveListModified;return 1;}command->UnRegister();}}if (this->ListModified) {elem = this->Start;this->ListModified = 0;}else {elem = next;}}}this->ListModified = saveListModified;return 0;
}unsigned long vtkSubjectHelper::GetTag(vtkCommand* cmd)
{vtkObserver* elem = this->Start;while (elem) {if (elem->Command == cmd) {return elem->Tag;}elem = elem->Next;}return 0;
}vtkCommand* vtkSubjectHelper::GetCommand(unsigned long tag)
{vtkObserver* elem = this->Start;while (elem) {if (elem->Tag == tag) {return elem->Command;}elem = elem->Next;}return nullptr;
}void vtkSubjectHelper::PrintSelf(ostream& os, vtkIndent indent)
{os << indent << "Registered Observers:\n";indent = indent.GetNextIndent();vtkObserver* elem = this->Start;if (!elem) {os << indent << "(none)\n";return;}for (; elem; elem = elem->Next) {elem->PrintSelf(os, indent);}
}

VTK源码阅读--vtkObject类-观察者/命令模式相关推荐

  1. Java源码阅读(类图自动生成工具)

    菜鸟上路,在有了基础以后,总需要去阅读大量的优秀的源码,但在面对一个项目工程大量的代码不知道怎么下手.只是跟着敲代码,我觉得这个方法不太妥当. 我是个方法论者,在收集查阅了大量的资料后发现画代码结构图 ...

  2. JVM源码阅读-Dalvik类的加载

    前言 本文主要研究Android dalvik虚拟机加载类的流程和机制.目的是了解Android中DEX文件结构,虚拟机如何从DEX文件中加载一个Java Class,以及到最终如何初始化这个类直至可 ...

  3. 【源码分析设计模式 13】命令模式

    一.基本介绍 1.在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作时哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计 ...

  4. VTK源码阅读--VTK里的智能指针vtkSmartPointer类

    vtkSmartPointer类 vtkSmartPointer是一个类模板,为vtkSmartPointerBase超类持有的对象提供自动强制转换. #ifndef vtkSmartPointer_ ...

  5. Mybatis源码阅读(四):核心接口4.1——StatementHandler

    *************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如 ...

  6. 24 UsageEnvironment使用环境抽象基类——Live555源码阅读(三)UsageEnvironment

    24 UsageEnvironment使用环境抽象基类--Live555源码阅读(三)UsageEnvironment 24 UsageEnvironment使用环境抽象基类--Live555源码阅读 ...

  7. webpack源码阅读——npm脚本运行webpack与命令行输入webpack的区别

    原文地址:webpack源码阅读--npm脚本执行webpack与命令行输入webpack执行的区别 如有错误,欢迎指正! webpack是目前被大家广为使用的模块打包器.从命令行输入webpack或 ...

  8. 16 BasicHashTable基本哈希表类(三)——Live555源码阅读(一)基本组件类

    这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类. 本文由乌合之众 lym瞎编,欢迎转载 http://www.cnblogs.com/oloroso ...

  9. surefire 拉起 junit 单元测试类 源码阅读(一)

    根据surefire 拉起Junit单元测试类 输出的报错日志 跟踪执行过程: 日志1: java.lang.reflect.InvocationTargetExceptionat sun.refle ...

最新文章

  1. Android中后台定时任务实现,即时数据同步问题思考!
  2. 【多重数组降维的简单方法】
  3. python基础面试题整理---从零开始 每天十题(04)
  4. UIView动画效果
  5. tensorflow gpu windows配置步骤教学
  6. windows下IDEA全面红色,但是能编译,不能智能提示
  7. latex 公式编号_放弃mathtype,word也可以轻松输入公式
  8. linux下DNS配置详解
  9. Linux NTP服务配置
  10. 汉诺塔问题的求解与分析
  11. SPSS异常值处理(图文+数据集)【SPSS 010期】
  12. 大学本科数学专业课程
  13. coolfire文章之七
  14. 用通俗易懂的方式讲解: GBDT算法及案例(Python 代码)
  15. 利用WinRAR自解压功能制作独立exe 程序
  16. MySQL 批量插入申请自增 ID
  17. 雨林木风SP3YN9.9 装机版09年09月更新(终结版)
  18. Jenkins+Gitlab+Ansible自动化部署(六)
  19. 程序员必备的量子力学知识
  20. AndroidCamera学习笔记一 硬件

热门文章

  1. 面试了一位 阿里出来的46 岁的程序员,思绪万千,最后结局居然...
  2. 【bug】vue.runtime.esm.js?2b0e:619 [Vue warn]: Failed to mount component: template or render function
  3. 将 字母 转换数字(1-26)
  4. matlab实训助教总结,助教自我评价简历范文
  5. Linux操作系统学习笔记【入门必备】
  6. 分享电脑日常使用的小技巧
  7. c语言怎么判断一个目录下面的文件是否为隐藏文件,怎么能显示出隐藏文件?...
  8. 华为Play 4T Pro批量添加联系人
  9. 原型模型概述及说明情况
  10. K8s介绍及离线安装(四)