To create a class of Base objects that supports persistence and
      that can be stored and restored using the
      SaveBase and LoadBase
      modules (see Section 8.2, “Composing, Storing and Retrieving Base Objects”), the following
      steps need to be taken:
Derive your custom class from Base or
            another class derived from Base (
              Section 2.1.2.3, “Base Field”
            ).
Include 
              mlTreeNode.h
             in your header
            file.
Overwrite the virtual methods
            addStateToTree() and
            readStateFromTree().
Assign a version number to your class by using the macro
            ML_SET_ADDSTATE_VERSION(VersionNumber) in
            your public class header.
Add the ML_CLASS_HEADER(ClassName)
            macro in the header.
Add the ML_CLASS_SOURCE(ClassName, SuperClassName) macro in the cpp.
Call YourClass::initClass() in the
            project's init.cpp file.
The following example shows how to implement persistence to a
      simple class SegmentedObject. The class
      SegmentedObject is derived from
      BaseItem which is derived from
      Base:
Base (abstract class, no members)
     |
BaseItem (name, id)
     |
SegmentedObject (objectGrayValue, voxelCount, boundingBox)Example 8.1. How to Implement Persistence for Base Objects
Header file of a class
        SegmentedObject:
class SegmentedObject : public BaseItem {
...
public:
      //! Implement export functionality (as used by the SaveBase module):
      virtual void addStateToTree(TreeNode* parent) const;
      // Set current version number
      ML_SET_ADDSTATE_VERSION(1);
      //! Implement import functionality (as used by the LoadBase module):
      virtual void readStateFromTree(TreeNode* parent);
private:
      //! ML runtime system related stuff
      ML_CLASS_HEADER(SegmentedObject);
      // Members to be (re-)stored:
      //! The identifying gray value of this object
      long _objectGrayValue;
      //! Number of voxels
      long _voxelCount;
      //! Bounding box respective to original image
      SubImageBox* _boundingBox;
...
}Source file of class
      SegmentedObject:
Adding the state to the tree:
//! Implement export functionality:
void SegmentedObject::addStateToTree(TreeNode* parent) const
{
  // Write version number (as set in the header)
  ML_ADDSTATE_VERSION(SegmentedObject);
  // Add superclass members:
  ML_ADDSTATE_SUPER(BaseItem);
  // Add this class' members:
  parent->addChild(_objectGrayValue, "ObjectGrayValue");
  parent->addChild(_voxelCount, "VoxelCount");
  // The bounding box is optional, do not write if the pointer is NULL:
  if (_boundingBox) { parent->addChild(*_boundingBox, "BoundingBox"); }
}Reading the state from the tree:
//! Implement import functionality:
void SegmentedObject::readStateFromTree(TreeNode* parent)
{
  // Read version number
  int version = parent->getVersion("SegmentedObject");
  // Read super class members:
  ML_READSTATE_SUPER(BaseItem);
  // Handle version differences:
  // In this example, version 0 used a different tag for _objectGrayValue
  // and did not write the VoxelCount value.
  switch (version) {
    case 0 :
      // Read object gray value from old tag name
      parent->readChild(_objectGrayValue, "GrayValue");
      break;
    case 1 :
      parent->readChild(_objectGrayValue, "ObjectGrayValue");
      break;
    default:
      // Throw exception: A version upgrade was performed without adapting the version handling
      throw TreeNodeException(TNE_UnsupportedClassVersion);
  }
  // Handle this version difference (voxelCount available or not)
  // by calling the macro ML_READCHILD_OPTIONAL which sets
  // the given variable to a default value (third parameter)
  // in case the tag "VoxelCount" was not found.
  ML_READCHILD_OPTIONAL(_voxelCount, "VoxelCount", 0);
  // Bounding box is optional:
  // However, ML_READCHILD_OPTIONAL is not designed for objects references,
  // hence we have to handle the case manually:
  if (!_boundingBox) { ML_CHECK_NEW(_boundingBox, new SubImageBox()); }
  try {
    parent->readChild(*_boundingBox, "BB");
  }
  catch (const TreeNodeException& e) {
    // Some other exception? Pass problem to caller.
    if (e.getCode() != TNE_ChildNotFound) { throw; }
    // No, a Child Not Found exception occurred, we handle it manually:
    ML_DELETE(_boundingBox);
  }
}Registering the class in the runtime type system:
ML_CLASS_SOURCE(SegmentedObject, BaseItem)
          © 2025 MeVis Medical Solutions AG