PDA

View Full Version : direct callback to my class method



paranada_g
03-05-2013, 02:19 AM
Hi,

I,m quite new in Ilog Views and need some kind of help to understand how it,s possible to root a callback from a button directly to a method of an class.

Until now, i have always done it throw a static method like this.

void ILVCALLBACK callback_methodName( (IlvGraphic* g, IlvAny)
{}

But what i want is to call straight to my class method

void MyClass::callback_methodCallback(IlvGraphic* g, IlvAny)
{
}

Might anyone give me a solutioni

Thank you very much indeed.

cmartin
03-05-2013, 02:43 AM
Hello,
The callback declaration needs to be of the type of: void (CALLBACKTYPE()) (IlvGraphic*, IlAny) but it can call your class method easily thus it is not possible to avoid the creating the function callback_methodName.

So it actually depends on your method declaration:
- either it is a static method from the class MyClass, then you can write:
void ILVCALLBACK callback_methodName (IlvGraphic* g, IlAny userData) {
MyClass::callback_methodCallback(g, userData);
}
- or it is not, thus you need to pass an instance of your class through either the IlvGraphic parameter if your class is a graphic class derived from IlvGraphic and the method is virtual or using the IlAny argument.
E.g. supposing your class is not a graphic one:
void ILVCALLBACK callback_methodName(IlvGraphic* g, IlAny userData) {
MyClass* my_obj = reinterpret_cast<MyClass*>userData;
my_obj->callback_methodCallback(g, userData);
}

HTH,
Claude

paranada_g
03-05-2013, 03:52 AM
Thank you.

These are both the ways i know. I thought there were some different ways like there are in qt or swing.

Thanks again.
:)

AMeurgues
04-12-2013, 08:14 AM
Hi,

There is a possible trick by using templates:

You can define a dedicated structure used to store the member function pointer, the object on which the function will be called and the IlAny parameter. It must be a template class, because we don't know which class the function is member of.


template <class Connected>
class MemberCallbackConnector {
public:

typedef void (Connected::* SlotType)(IlvGraphic*,IlAny);

MemberCallbackConnector(Connected& b, SlotType s, IlAny arg=0) : receiver(b), slot(s), any(arg) {}
void call(IlvGraphic* g) { (receiver.*slot)(g,any); }
private:

Connected& receiver;
SlotType slot;
IlAny any;
};

Then, you can write a generic callback that will extract this structure from the IlAny parameter and call the member function slot on the object receiver:


template<class Connected>
void MemberCallbackConnectorCB(IlvGraphic* g,IlAny any) {

MemberCallbackConnector<Connected>* connector = static_cast<MemberCallbackConnector<Connected>*>(any);
connector->call(g);
}

Finally, you need a function to set the callback. It will create the structure and register the generic callback, with the structure added as IlAny paramater:


template<class Connected>
void Connect(IlvGraphic& a,const IlSymbol* symbol,Connected& b, void (Connected::* s)(IlvGraphic*,IlAny),IlAny any=0) {

a.addCallback(

symbol, // for a given callback symbol
&MemberCallbackConnectorCB<Connected>, // a generic CB
static_cast<IlAny>(new MemberCallbackConnector<Connected>(b,s,any)) // that will call a constructed functor
);
}

You then can call this Connect function when you want to use a member function as a callback:


struct AnyObject {

void testCB(IlvGraphic* g,IlAny) { IlvPrint("AnyObject::testCB"); }
AnyObject (IlvGadget* g) { Connect(*g,IlvGadget::CallbackSymbol(),*this,&AnyObject ::testCB); }
};

Here, the constructor of AnyObject will install a callback on the gadget g which will execute its member function AnyObject::testCB.

This is a bit tricky, but it works. The only drawback is that this structure is never deleted. It might be necessary to use some member callback collector manager in order to avoid memory leaks.