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)
© 2024 MeVis Medical Solutions AG