Writing own objects
Writing own objects is quite simple: You have to create a class which is derived from the objects base class VimmsObject.
The source file is compiled to a shared library and loaded within Vimms using the module dialog. When using the predefined property dialog and creating no control windows for user interaction (nearly) no knowledge of window system programming or the Qt class library is needed (maybe sometimes for basic classes like QString when using string variables).
This page describes the basic steps needed to write an own Vimms object that does not have an associated control window:
- Use the source file templates noviewertemplate.cpp and noviewertemplate.h and copy
them to files with different name, for example "myobject.cpp" and "myobject.h". It is best to create a separate subdirectory
for these files within the directory containing the source files of Vimms.
- Open the files in a text editor and rename every occurrence of the word "TemplObject" into an object name of your choice,
we choose "MyObject" in this example. Do this for both the source and the header file.
- Create an object icon as 32x32 pixel image and save it as an .xpm file. Open the .xpm file in a text editor.
The second line starts with static char *..., change this to static const char *.... This
is for suppressing a compiler warning when including this file in the myobject.cpp. Remember the identifier behind the asterisk, this
is the variable name under which the pixmap data is accessible.
- Add an include statement for the .xpm file at the top of myobject.cpp, eventually removing the existing .xpm include statement.
Then locate the function GetIcon() and change the identifier in the Pixmap(...) constructor to the identifier
in the newly created .xpm file.
- Specify the object name which should appear in the object container as the return value
of the function GetName(). Specify a short object description as return value of the function
GetDescr().
- Create input and output variables as well as object properties. Variables and properties are defined
within the function CreateVars(). For detailed information about creation
and usage of variables and properties look here.
- Inititalize all class member variables that are controlled by properties. The initialization should be done in the object's constructor.
- Write the code for initialization and deinitialization of the object. When execution is startet, the object's function bool InitObject() is called. On successful initialization this function should return true. If it returns false, the object is disabled and the status indicator is set red. This can be used for example for checking the status of external devices and indicate an error if it could not be initialized.
When execution is switched off and all threads have terminated, the function void StopFunction() of all objects is called. Here the object's deinitialization can be done.
- Write the code for the object's standard action in function bool WantData(). Within this function all input and output variables can be accessed.
- Optionally create additional actions. Creating actions is also done within the function CreateVars(). The following line of code shows how to create a user defined action:
TCaller("User Action",this,&MyObject::MyAction))->InsertInto(Actions);
The example creates an action called "User Action". This action calls a function bool MyObject::MyAction(), which must be a valid function declared in the header file. This function is similar to the standard action WantData with the difference that it is called when the user selects "User Action" in the action list.
- When creating a shared object file and not extending the Vimms main program provide a function extern "C" void GetObjectList(int& count, TObjectCreatorBase**& objects,QString& grp). This function is called from Vimms to get information about the objects defined in the shared object file.
Multiple objects can be defined in a single file. Set count to the number of objects that are defined in the file. The objects variable must be set to a pointer array to instances of TObjectCreator (defined in objectlister.h). For each defined object one instance. The usage of the parameters is demonstrated in the example file image.cpp:
extern "C" void GetObjectList(int& count, TObjectCreatorBase**& objects,QString& grp) {
count = 1;
objects = new TObjectCreatorBase*[1];
objects[0] = new TObjectCreator<ImageObject>;
grp = "User Defined";
};
Here an array with a single entry is created. An icon belonging to ImageObject is added to the group "User Defined".
When extending the Vimms main program add the file to the Vimms project, add an include statement for the header file in objectlister.h and add the TObjectCreator instance for the object.
- If creating a shared object file compile it with the following statement (example for image.cpp):
g++ image.cpp -o image.so -shared -rdynamic -I.. -I/usr/lib/qt3/include
This works if the source file are in a subdirectory of the Vimms source files. Otherwise change parameter -I.. to point to the location of the Vimms source files.
That's all for writing standard objects without a viewer window.
Defining own property dialogs
For extending the functionality of property dialogs there are two possibilities:
- Define specialized properties that provide a button in the property dialog for performing additional functions like opening another dialog. This is used for example to display the curve properties within the graphic object. For doing this one must create a class derived from TSpecialProperty. I do not document this here because it is used only seldom, for more information look in the source code of the graphic object graphobj.cpp
- Provide an own version of the function void doubleClick(Objedit* sender). This function is called when the user double clicks on the object icon.
Now I like to describe the second possibility, as one can do most sophisticated things with this. I want to start with a sample from the VarBridge object which displays an own property dialog. As all property dialogs are modeless, i.e. the user can continue work with the program or open other dialogs, one has to take care that the property dialog of the same object is not opened multiple times. Also all property dialogs should be closed when execution is started as changing properties during runtime may desturb the communication between the execution process and the user interface. Therefore the VimmsObject class provides a variable activePropDialog that holds a pointer to the currently open property dialog of each object or NULL if there is no property dialog displayed. Each object has to set and to check this variable when overwriting the function doubleClick:
void VarBridge::doubleClick(Objedit* sender) {
if (activePropDialog) {
activePropDialog->raise();
activePropDialog->setActiveWindow();
return;
};
activePropDialog = new VarBridgeDialog(this,sender);
activePropDialog->setCaption("Properties of "+title);
... some initialization ...
activePropDialog->show();
};
In this example it is first checked whether there is already a property dialog open. If yes, then this dialog is raised to the front instead of opening another dialog. In the other case the user define dialog window is opened. This window should be derived from QWidget or QDialog and the parameter of the doubleClick function should be passwd as the new dialog's parent. Now the dialog can be displayed and change some class variables.
But one thing is missing: How to store the values that were entered in the user defined dialog? All vimms objects are derived from a special class TPersistObject (source code in filter.cpp) which is responsible for writing objects into a file and restore them out of the file again. A class can be written into a file if it is derived from TPersistObject and the macros IMPLEMENT_PERSISTENT and DECLARE_PERSISTENT were used as in the template file. For storing and reading back values one has to provide two functions void WriteTo(QDataStream& ds) and void ReadFrom(int version,QDataStream& ds). When saving a vimms project file do disc or storing the project into the undo buffer, the function WriteTo is called. For usage of the class QDataStream take a look in the Qt documentation. All data stored into the QDataStream in the function WriteTo should be read out in the function ReadFrom when the object is restored. The parameter version returns the version of the object which has been stored. This version number normally is 1 and can be changed when providing an own function int GetCurrentVersion() (defined in filter.h). When overwriting the functions ReadFrom and WriteTo don't forget to call the overwritten function of the base class before doing anything else.
When an object is restored from the disc, a different constructor is used. In the template file it is defined by the following line:
TemplObject(PersistInit):VimmsObject(persistInit) {};
Here variables should be initialized which are not stored to disk. Normally this constructor does nothing as there exists another function void InitNonPermanent(int version) which is called in both cases when an object is restored from disk and when it is newly created. When overwriting this function also at first VimmsObject's InitNonPermanent function should be called. If the object is restored from disc than the version number may be smaller than the current version number which can be used for doing special initialization for objects that are restored from an older version. The function InitNonPermanent is always called before ReadFrom.
Back
Vimms user manual
F. Hitzel, 2003