An Example: Dynamic Access
The purpose of this example is to make a graphic class dynamically accessible from a running application.
Let us suppose that we have a class CrossedRectangle, deriving from IlvFilledRectangle, that is displayed as an outlined rectangle with a cross in it. The example is developed in:
Writing the Sample Module Definition File
First, you have to make sure that Views properly loads the code of this class when a data file refers to its name, thus allowing the corresponding module to be implicitly loaded.
To that end, we have to write a module definition file, which in our example will be very simple since we only have one class.
Here is the content of an appropriate module definition file for this module. Since we have only one class, whose root base class is IlvGraphic, the definition file is as follows:
<?xml version = "1.0"?>
<module name="correct" version="1.0">
<class name = "CrossedRectangle" rootClass = "IlvGraphic"/>
</module>
We could have added many other classes to this module definition file, even classes that do not inherit from IlvGraphic. You can add classes to the same module in an incremental way.
Implementing the New Class
Once the module definition file is written, we have to do some more work to implement this new class. The specifications are quite simple:
-
Create a filled rectangle that displays a cross inside a frame.
-
Make sure that this new class is persistent.
-
Add this class to a dynamic module.
Although you are probably already familiar with the first two steps, we provide the corresponding code below. The last point represents the most difficult part. We must need to know how we are going to proceed to register our class properly. Unfortunately, the macro IlvRegisterClass does not work in a dynamic loading context, or at least not in a portable way. Views provides a few macros very close to the ones that you are already familiar with for solving this problem. We will discuss them after you see the code for the CrossedRectangle class, which is given below.
#include <ilviews/graphics/rectangl.h>
class CrossedRectangle
: public IlvFilledRectangle {
public:
CrossedRectangle(IlvDisplay* display,
const IlvRect& size, IlvPalette* pal=0)
: IlvFilledRectangle(display, size, pal)
{}
virtual void draw(IlvPort* dst, const IlvTransformer* t = 0,
const IlvRegion* clip = 0) const;
DeclareTypeInfoRO();
DeclareIOConstructors(CrossedRectangle);
};
// Copy constructor
CrossedRectangle::CrossedRectangle(const CrossedRectangle& source)
: IlvFilledRectangle(source)
{}
// Read constructor
CrossedRectangle::CrossedRectangle(IlvInputFile& is,
IlvPalette* pal)
: IlvFilledRectangle(is, pal)
{}
void
CrossedRectangle::draw(IlvPort* dst, const IlvTransformer* t,
const IlvRegion* clip) const
{
if (clip)
_palette->setClip(clip);
IlvRect r = _drawrect;
if (t)
t->apply(r);
dst->drawRectangle(_palette, r);
dst->drawLine(_palette, r.upperLeft(), r.lowerRight());
dst->drawLine(_palette, r.upperRight(), r.lowerLeft());
if (clip)
_palette->setClip();
}
IlvPredefinedIOMembers(CrossedRectangle)
The draw method is straightforward.
You can see that, as required, this class contains a copy constructor and persistence-related methods. (It has no write method since we do not have any information to save, and so we used the DeclareTypeInfoRO macro in the class declaration).
We have already addressed two of the three points for implementing the new class.
The usual way to register this class with the Views persistence mechanism would be to use the well-known statement:
IlvRegisterClass(CrossedRectangle, IlvFilledRectangle);
which appears outside the body of any function.
If an application links with that code, it will be able to manipulate, save, and read instances of the class CrossedRectangle. Remember, however, that you want to make the CrossedRectangle class known to existing applications that were not aware of it when they were developed so that they can read data files generated by applications in which this class is defined. To do so, you have to plug this class into a dynamic module, and you cannot use the preceding macro for this purpose.
Loading and Registration of the Example
It is important to understand what happens when a module is loaded and what registration actually does:
-
When a module is loaded, its constructor is called.
-
Registration is both the declaration of class-level variables that store class-level attributes and function calls that actually update these variables.
With the dynamic modules feature, Views provides an alternate form of the IlvRegisterXXXClass macros, which are used in many places (in IlvGraphic and IlvNamedProperty subclasses, for example). This set of macros separates the declaration part of the registration from its definition.
The name of the macro used for the declarative part of the registration is similar to IlvRegisterXXXClass, except that IlvRegister is replaced by IlvPreRegister. The second parameter of IlvRegisterXXXClass is dropped. This macro call must appear outside the body of any function (it declares only class-level variables).
The name of the macro used for the definition part of the registration is similar to IlvRegisterXXXClass, except that IlvRegister is replaced by IlvPostRegister. The second parameter of IlvRegisterXXXClass remains. Thus, macro calls must appear inside the body of a function that must be called to actually perform the proper registration (it does call code to register new classes).
In our example, to register the graphic class, we have to use both the macros IlvPreRegisterClass (outside the body of any function) and IlvPostRegisterClass (inside the body of a function).
Registration Macros
Below is a list of the macros that you must use for registering most of the Views classes that are persistent (c indicates the class name that is being registered, and s indicates its parent class name):
Class Name |
Static Registration Macros | Registration Macros in Dynamic Modules |
IlvRegisterClass(c, s); | IlvPreRegisterClass(c);IlvPostRegisterClass(c, s); | |
IlvNamedProperty | IlvRegisterPropertyClass(c, s); | IlvPreRegisterPropertyClass(c);IlvPostRegisterPropertyClass(c, s); |
IlvView | IlvRegisterViewClass(c, s); | IlvPreRegisterViewClass(c);IlvPostRegisterViewClass(c, s); |
IlvGadgetItem | IlvRegisterGadgetItemClass(c, s); | IlvPreRegisterGadgetItemClass(c);IlvPostRegisterGadgetItemClass(c, s);For details on gadgets, refer to the Gadgets documentation. |
IlvNotebookPage | IlvRegisterNotebookPageClass(c, s); | IlvPreRegisterNotebookPageClass(c);IlvPostRegisterNotebookPageClass(c, s); |
IlvSmartSet | IlvRegisterSmartSetClass(c, s); | IlvPreRegisterSmartSetClass(c);IlvPostRegisterSmartSetClass(c, s); |
IlvGroup | IlvRegisterGroupClass(c, s); | IlvPreRegisterGroupClass(c);IlvPostRegisterGroupClass(c, s); |
IlvGroupNode | IlvRegisterGroupNodeClass(c, s); | IlvPreRegisterGroupNodeClass(c);IlvPostRegisterGroupNodeClass(c, s); |
IlvUserAccessor | IlvRegisterUserAccessorClass(c, s); | IlvPreRegisterUserAccessorClass(c);IlvPostRegisterUserAccessorClass(c, s); |
Because we are dealing with a subclass of IlvGraphic, the IlvPreRegisterClass and IlvPostRegisterClass macros are all we need to complete the source code of our module.
Adding the Sample Class to a Dynamic Module
Here is the code that we have to add to the definition of the CrossedRectangle class to make the final source code compilable as a Views dynamic module:
#include <ilviews/base/modules.h>
IlvPreRegisterClass(CrossedRectangle);
class MyModule
: public IlvModule
{
public:
MyModule(void*)
{
IlvPostRegisterClass(CrossedRectangle, IlvFilledRectangle);
}
};
ILVINITIALIZEMODULE(MyModule);
Note that you can add this code to a #if defined()/#else/#endif precompiler block, with the regular
IlvRegisterClass(CrossedRectangle, IlvFilledRectangle);
in the #else part of if. You will then be able to compile your code as a regular static object file or as a dynamic module:
#if defined(MAKE_A_MODULE)
#include <ilviews/base/modules.h>
IlvPreRegisterClass(CrossedRectangle);
class MyModule
: public IlvModule
{
public:
MyModule(void*)
{
IlvPostRegisterClass(CrossedRectangle, IlvFilledRectangle);
}
};
ILVINITIALIZEMODULE(MyModule);
#else /* DONT_MAKE_A_MODULE */
IlvRegisterClass(CrossedRectangle, IlvFilledRectangle);
#endif /* DONT_MAKE_A_MODULE */