Signal/slot


#1

Hi,

I was wondering if the use of the Listener system is definite :slight_smile:

I currently use a signal/slots system based on
FastDelegate
http://www.codeproject.com/cpp/FastDelegate.asp

and it works fine.

Libsigc++ is LGPL and very big so it would be hard to add to it to JUCE,
but I would be happy to share my code based on FastDelegate.

http://littlejourney.net/JUCE/

Let me know what do you think.

Thanks,


#2

This comes up occasionally, but I really quite like the listeners… With a listener model, all the callbacks use fixed names, so when you look at a class you can see exactly what’s going on, rather than having to work out which bits are connected together.

But of course, if anyone can post some convincing examples of where a signal/slot mechanism would make code easier to write or understand, I’m open to persuasion.


#3

i use that FastDelegates in a more simpler manner. i just use that in my Parameter system, to not force the parameters to be sticked to any hardcoded function belonging to a specific class / the only requirement is to follow the getter or setter signature)

[code]class Parameter : public AsyncUpdater
{
protected:
typedef FastDelegate2<float, void> SetDelegate;
typedef FastDelegate1 GetDelegate;

inline float getValue () {
    return getterFunction ();
}

[/code]

so when i build the parameters i can attach my parameter to real functions inside the dsp classes i already have in my effects or synths.

this way i can do obtrusive things like this:

plugin.register (parameters[x].name (T("filter gain")) .unit (T("db")) .range (0,1) .mapping (DB) .set (MakeDelegate (this, &MyFilter::set_gain)) .get (MakeDelegate (this, &MyFilter::get_gain)));

without publish parameters outside MyFilter, and eventually this let me switch the getter and setter at runtime, while maintining the parameter implementation clean.


#4

[quote=“jules”]This comes up occasionally, but I really quite like the listeners… With a listener model, all the callbacks use fixed names, so when you look at a class you can see exactly what’s going on, rather than having to work out which bits are connected together.

But of course, if anyone can post some convincing examples of where a signal/slot mechanism would make code easier to write or understand, I’m open to persuasion.[/quote]

I ll cook some example.

One of the cool thing is, it allows to have C function as callback
and do not require to have some switch case stuff if you connect to same events on multiple widgets.

Thanks,


#5

Here is a working example:

http://littlejourney.net/JUCE/


#6

Hi,

I took a look look at the fast FastDelegate, and I must say I’m a little bit sceptical. It may work, it may be efficient. But it uses so many compiler-specific implementation details, it looks to me like a ticking timebomb.

And for my use the delegates of the boost library are an overkill. I also don’t like that the so called “preferred syntax” which is used througout the documentation, is not portable:

http://www.boost.org/doc/libs/1_35_0/doc/html/function/tutorial.html

So I made my own delegate template :D, which is simple and fully standard compatible (at least so I think):

http://www.noloops.ch/source/delegate.h

There are different template classes dependent on the number of parameters and if there is a return type( the code was created using a generator). The usage is quite simple:

class MyClass
{
public:
	void myMethod() { }
	virtual void myVirtualMethod() { }
	static void myStaticMethod() { }
};

void mySub() { }

MyClass gMyClass;


void example()
{
		DelegateV0 f; // V0 means void, zero parameters

		f.bind<&mySub>();
		f();
		f.bind<&MyClass::myStaticMethod>();
		f();
		f.bind<MyClass, &MyClass::myMethod>(&gMyClass);
		f();
		f.bind<MyClass, &MyClass::myVirtualMethod>(&gMyClass);
		f();
}

I wrote a first testcase with projects for Visual C++, Borland C++ Builder and Xcode (the code works also fine with GCC, tested under linux). You can download it here:

http://www.noloops.ch/source/Delegate.zip

The Implementation of the most simple case (no return value, no parameters, therefore a class instead of a template class) looks like this (here only the important methods are shown, but it is still functional):

class DelegateV0
{
	typedef void (*Caller)(void *obj);
public:
	DelegateV0() : caller(0), obj(0) { }

	template< void (*M)() >
	inline void bind()
	{
		obj    = 0;
		caller = staticCaller<M>;
	}


	template<class ObjectType, void (ObjectType::*M)() >
	inline void bind(ObjectType *inObj)
	{
		bindMethod(inObj, methodCaller<ObjectType, M>);
	}

	inline void operator () () 
	{ 
		caller(obj);
	}

	inline bool isNull()   { return caller == 0; }

private:
	template< void (*M)() >	
	static void staticCaller(void *obj)
	{
		(*M)  ();
	}

	template<class ObjectType, void (ObjectType::*M)() >
	static void methodCaller(void *obj)
	{
		(static_cast<ObjectType*>(obj)->*M)  ();
	}

	void bindMethod(void *inObj, Caller inCaller)
	{
		obj    = inObj;
		caller = (obj) ? inCaller : 0;	
	}

	Caller caller;
	void *obj;
};

In my oppinion, such a signal/slot mechanism is a great thing to implement a loose coupling between components. What do you think?
I would be very pleased about any feedback.

Greetings
Jan


#7