Template based Slider handler


#1

Since I’m not a big fan of if, else if, else if a.s.o. I’ve made a handy little template and STL based dispatcher of Slider events:

[code]//////////////////////////////////////////////////////////////////////////

#ifndef SLIDERLISTENERHANDLER
#define SLIDERLISTENERHANDLER

#include <juce.h>
#include

template
class SliderListenerHandler : public SliderListener
{
protected:
typedef void (T::sliderCallback)(const double);
typedef std::map<Slider
, sliderCallback> cbmap_type;
cbmap_type cbSliderMap_;

void addSliderHandler(Slider* pSlider, sliderCallback callback)
{
	pSlider->addListener(this);
	cbSliderMap_[pSlider] = callback;
}

public:
/** Called when the slider is moved /
virtual void sliderValueChanged (Slider
slider)
{
typename cbmap_type::iterator it = cbSliderMap_.find(slider);
if (it != cbSliderMap_.end())
{
(((T*)this)->*(it->second))(slider->getValue());
}
}
};

#endif[/code]

Put that in a SliderListenerHandler.h file and use it in your component as:

[code]class MyComponent : public SliderListenerHandler
{

void mySliderChanged(const double value);

Slider* mySlider;

}
[/code]
and somewhere in implementation (where you create mySlider):

   addSliderHandler(mySlider, &MyComponent::mySliderChanged);

Now all calls from mySlider will end up in mySliderChanged :slight_smile:

/R


#2

i don’t understand the point of this… and it makes for some slightly unpleasant looking code…

but well done anyway, it doesn’t matter what i think, it’s just not for me!


#3

[quote=“haydxn”]i don’t understand the point of this… and it makes for some slightly unpleasant looking code…

but well done anyway, it doesn’t matter what i think, it’s just not for me![/quote]

Even though it can look “unpleasant”, it is still C++, and besides, it is hidden in a template so you won’t have to bother with it :slight_smile:

Ok, with only one slider I see why you don’t understand the point of it… The point is when you have a LOT of sliders in your GUI. Then you can get rid of the if/elseif/elseif/… which I see as UC (ugly-code), but then again that is my highly personal belief :wink:

Anyway, here’s a version for buttons:

[code]//////////////////////////////////////////////////////////////////////////

#ifndef BUTTONLISTENERHANDLER
#define BUTTONLISTENERHANDLER

#include <juce.h>
#include

template
class ButtonListenerHandler : public ButtonListener
{
protected:
typedef void (T::buttonCallback)(Button);
typedef std::map<Button*, buttonCallback> cbmap_type;
cbmap_type cbClickMap_;
cbmap_type cbStateChangeMap_;

void addButtonClickHandler(Button* pButton, buttonCallback callback)
{
	pButton->addButtonListener(this);
	cbClickMap_[pButton] = callback;
}
void addButtonStateChangeHandler(Button* pButton, buttonCallback callback)
{
	pButton->addButtonListener(this);
	cbStateChangeMap_[pButton] = callback;
}

public:
/** Called when the button is clicked. /
virtual void buttonClicked (Button
button)
{
typename cbmap_type::iterator it = cbClickMap_.find(button);
if (it != cbClickMap_.end())
{
(((T*)this)->*(it->second))(button);
}
}

/** Called when the button's state changes. */
virtual void buttonStateChanged (Button* button)
{
	typename cbmap_type::iterator it = cbStateChangeMap_.find(button);
	if (it != cbStateChangeMap_.end())
	{
		(((T*)this)->*(it->second))(button);
	}
}

};

#endif
[/code]

which pretty much follows the same idiom. You get the idea…

/R


#4

that still doesn’t permit you to attach buttons to object different to the one specified in your templatized listener constructor (and somehow is a bit intrusive by the forced use of the templatized parameter).

instead, if i would use such a syntax, i’ll stick with delegates (or member - functors). look here, it works quite well and doesn’t limit you to templatize everything: http://www.codeproject.com/cpp/FastDelegate.asp

i would have something like this (an example stright out of my head):

class ButtonListenerHandler : public ButtonListener
{
protected:
   typedef FastDelegate1<Button*, void> ListenerDelegateCallback;
   typedef std::map<Button*, ListenerDelegateCallback> DelegateMap; 
   DelegateMap listenerMap;

   void addButtonHandler (Button* pButton, ListenerDelegateCallback callback)
   {
      pButton->addButtonListener(this);
      listenerMap[pButton] = callback;
   }

public:
   /** Called when the button is clicked. */
   virtual void buttonClicked (Button* button)
   {
      typename DelegateMap::iterator it = listenerMap.find(button);
      if (it != listenerMap.end())
      {
         *(it->second)(button);
      }
   }

   /** Called when the button's state changes. */
   virtual void buttonStateChanged (Button* button)
   {
      typename DelegateMap::iterator it = listenerMap.find(button);
      if (it != listenerMap.end())
      {
         *(it->second)(button);
      }
   }

};

(even if i wouln’t use the std::map)
so you’ll be able to link something not strictly to your object, or having your Component derive from s slider listener templatized to himself
(don’t like the “class MyComponent : public SliderListenerHandler”).

and still you can link to something like:

MyComponent::MyComponent ()
{
  addButtonHandler (myButton, MakeDelegate (this, &MyComponent::setSomethingChanged));
 
  addButtonHandler (myButton, MakeDelegate (&myMemberDspObject, &MyDSPobject::somethingMoreChanged));
}

the example is speaking about the usage… this is miles less intrusive and lets you attach practically anything to your button, and not being limited to your MyComponent !


#5

[quote=“kraken”]instead, if i would use such a syntax, i’ll stick with delegates (or member - functors). look here, it works quite well and doesn’t limit you to templatize everything: http://www.codeproject.com/cpp/FastDelegate.asp
[/quote]

Indeed, that’s nice! I’ve used that delegate impl on some occasions, although for this particular purpose where the parent is normally interested in the subcomponent events, I opted for the simpler templated approach.

All the best,
/R


#6

Don’t use FastDelegate, it is vastly incomplete compared to the standard.
The next version of C++ is coming with a vastly better one, compiles to the same assembly as FastDelegate (which is as small as such calls can get), is pleasent to use, and (worth saying again) is the ‘standard’. If you want to use it now you can get the C++0x RC1 pack from boost, which are all the boost specific things that are being removed from boost since they are accepted into the standard, or just download boost in full and use boost::function. It will work in just about any compilier (they are boost after all, they find ways to make just about everything work everywhere).


#7

sure, it is vastly incomplete, and nothing compared to boost::function (try to use boost::function in inner loops! yawn…). but regarding the standards, it will compile on vc6 - vs8 - gcc3 - gcc4 - xcode on intel32bit and on G4/G5 ppc. Do you actually use digital mars ?

i’m waiting what the new standard will say… sure delegates is a builtin-must-have for a perfect c++ compiler. i’m patient… but it will take too much time imho !!!


#8

Ergo, just go download the RC1 pack which is the pack of new objects that are already accepted into the next standard, but will work with current compilers, boost::function (std::function) is in it. And boost::function compiles on near everything, so no worry.


#9