IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发工具 -> VTK源码阅读--vtkObject类-观察者/命令模式 -> 正文阅读

[开发工具]VTK源码阅读--vtkObject类-观察者/命令模式

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 vtkWeakPointer

class vtkSubjectHelper;
class vtkCommand;

class VTKCOMMONCORE_EXPORT vtkObject : public vtkObjectBase
{
public:
  vtkBaseTypeMacro(vtkObject, vtkObjectBase);

  // 创建一个对象,关闭Debug标识;
  // 时间戳初始为0,启用引用计数
  static vtkObject* New();

#ifdef _WIN32
  // avoid dll boundary problems
  void* 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 them
  vtkTypeBool 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);
  }

  // 允许用户使用回调方法的返回值设置AbortFlagOn
  template <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;
  // 事件ID
  unsigned long Event;
  // Tag ID
  unsigned 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类型事件中是否包含vtkEventData
  static 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_event

protected:
  // 中断类型
  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";
#endif

vtkCommand::vtkCommand()
  : AbortFlag(0)
  , PassiveObserver(0)
{
#ifdef VTK_DEBUG_LEAKS
  vtkDebugLeaks::ConstructClass(leakname);
#endif
}

void vtkCommand::UnRegister()
{
  int refcount = this->GetReferenceCount() - 1;
  this->SetReferenceCount(refcount);
  if (refcount <= 0) {
#ifdef VTK_DEBUG_LEAKS
    vtkDebugLeaks::DestructClass(leakname);
#endif
    delete this;
  }
}

const char* vtkCommand::GetStringFromEventId(unsigned long event)
{
  switch (event)  {
#define _vtk_add_event(Enum)                                                                       \
  case Enum:                                                                                       \
    return #Enum;

  vtkAllEventsMacro()

#undef _vtk_add_event
    case 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_event

    if (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*);
  // 判断观察者列表中是否含有相同的event
  vtkTypeBool 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 first
    vtkObserver* 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 loop
          focusHandled = 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 Command
      next = 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 location
          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;
      }
    }
  }

  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);
  }
}

  开发工具 最新文章
Postman接口测试之Mock快速入门
ASCII码空格替换查表_最全ASCII码对照表0-2
如何使用 ssh 建立 socks 代理
Typora配合PicGo阿里云图床配置
SoapUI、Jmeter、Postman三种接口测试工具的
github用相对路径显示图片_GitHub 中 readm
Windows编译g2o及其g2o viewer
解决jupyter notebook无法连接/ jupyter连接
Git恢复到之前版本
VScode常用快捷键
上一篇文章      下一篇文章      查看所有文章
加:2022-05-18 17:51:32  更:2022-05-18 17:53:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 0:31:00-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码