Callback from Array<PropertyComponent*>

gui

#1

Hello,
I liked the PropertiesDemo example in the Juce Demo, but stuck with the choice made of adding pointers of class DemoSliderPropertyComponent to an array of PropertyComponent*.
Could someone be kind enough to illustrate the way we can get callback from the sliders in this specific example ?


#2

The DemoSliderPropertyComponent class in the JUCE Demo inherits from SliderPropertyComponent so you can access its protected Slider member and attach a listener to it. You’ll need to inherit from Slider::Listener and then call slider.addListener (this) in the constructor. Then implement the listener’s sliderValueChanged() method, which will be called whenever the Slider value changes.


#3

This is clear for me. What is less clear is how to get it working in the context of the PropertiesDemo example. I would really need that for a better understanding.
In the example, demoSliderComponents are added to an array of PropertyComponent. When I create a demoSliderComponent, I can’t do slider.addListener with this newly added component.
Let’s say I do the following:
Considering displayLimits is defined like this, in order for being able to be added to the main propertyPanel with the function addSection() :

	Array<PropertyComponent*> displayLimits;

Then when I write the following code:

		DemoSliderPropertyComponent* s = new DemoSliderPropertyComponent ("Something rich and strange");
	displayLimits.add (s);
	s->addListener(this);

(‘this’ implementing Slider::Listener),
I get: “No member named addListener in DemoSliderPropertyComponent”


#4

Well no that won’t work as DemoSliderPropertyComponent isn’t a Slider, it just contains one as a child component. If you wanted to do something like your example, you’d need to expose its Slider as a public member or have getter method then you could do:

s->slider.addListener (this);

What are you trying to achieve though? You’ll probably be better off just using a SliderPropertyComponent to control a Value object that you can listen to. So you’d have some member variables like this:

OwnedArray<PropertyComponent> propertyComponents;
Value valueToControl;

and then in your constructor:

valueToControl.addListener (this);
...
propertyComponents.add  (new SliderPropertyComponent (valueToControl, "SliderProperty", 0.0, 1.0, 0.1));

Now if your parent class inherits from Value::Listener and implements its valueChanged() method you will get a callback whenever the user moves the Slider and changes its underlying Value.


#5

Thanks, that looks nice. However I tried the following and could not monitor any change from the Slider, could you tell where I got wrong ?:

class SettingsGUI : public Component, public Value::Listener, public Slider::Listener
{

public:
SettingsGUI()
{
	PropertyPanel*  panel = new PropertyPanel ("Project Settings");
	valueToControl.addListener(this);
	someSliders.add (new SliderPropertyComponent (valueToControl, "valueOfSomeKind", 0.0, 1.0, 0.1));
	panel->addSection("Special", someSliders, true);
}
void valueChanged (Value &value) override
{
	DBG(" valchgd: " << value.toString());
}
private:
Array<PropertyComponent*> someSliders;

};


#6

Here is a really minimal working example:

//==============================================================================
class MainContentComponent   : public Component,
                                  private Value::Listener
{
public:
    //==============================================================================
    MainContentComponent()
    {
        valueToControl.addListener (this);
        
        sliderProps.add (new SliderPropertyComponent (valueToControl, "Slider", 0.0, 1.0, 0.01));
        propPanel.addSection ("Sliders", sliderProps);
        
        addAndMakeVisible (propPanel);
        
        setSize (600, 400);
    }
    
    ~MainContentComponent() {}

    void paint (Graphics& g) override
    {
        g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));
    }
    
    void resized() override
    {
        propPanel.setBounds (getLocalBounds().reduced (5));
    }

private:
    void valueChanged (Value& v) override
    {
        DBG ("Value changed");
    }
    
    Value valueToControl;
    Array<PropertyComponent*> sliderProps;
    PropertyPanel propPanel;
    
    //==============================================================================
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
};

#7

Well, thanks and sorry for my last complaint: I don’t why, but my own code was working, in fact.
While we are getting to the core of the question: how do I distinguish in this example, which slider has issued the value (if I add more sliders) ?


#8

The valueChanged() callback is called with a reference to the Value that has been modified as its argument, so you can compare this to your Value members to determine which has changed.


#9

Great, that worked!
I am not used to Values, so did’nt know the easiest way.
Thanks