What is the best way to create a "variable listener."

In other words, if I had a float variable “foo,” what would be the best way to create a listener for changes to that variable? I don’t want to use value trees because I don’t want the user to be able to automate this value in the host but I want to be able to able to trigger functions and fun things to happen when the variable changes.

Plain primitive types like floats can’t be “listened” for changes. You could poll the value repeatedly however in some suitable place that gets repeatedly executed. (But then you’d also need to keep a “lastValue” variable to know if the value has changed since the last time…)

You could maybe look into the Juce Value and Value::Listener classes, those can be also used by themself without ValueTrees.

“You could maybe look into the Juce Value and Value::Listener classes, those can be also used by themself without ValueTrees.”

That’s exactly what I needed, thanks!

a great exercise is to write your own wrapper class that adds this functionality to whatever type you want notifications to. a simple combination of inheriting from AsyncUpdater, overloading operator= and the conversion operator will give you this functionality.

template<typename T>
struct Wrapper : private AsyncUpdater
{
    struct Listener
    {
        virtual ~Listener() { }
        virtual void valueChanged(const Wrapper& w) const { }
        std::function<void()> onValueChanged;
    };
    Wrapper& operator=(const T& other)
    {
        data = other;
        triggerAsyncUpdate();
    }
    operator T() const
    {
        return data;
    }
    void addListener(Listener* l) { listeners.addIfNotAlreadyThere(l); }
    void removeListener(Listener* l) { listeners.removeFirstMatchingValue(l); }
private:
    void handleAsyncUpdate() override
    {
        for( int i = listeners.size(); --i >= 0; )
        {
            auto* l = listeners.getUnchecked(i);
            l->valueChanged(*this);
            if( l->onValueChanged ) l->onValueChanged();
        }
    }
    T data { };
    Array<Listener*> listeners;
};

note: untested code, but you get the idea…

3 Likes