How to add one callback for multiple ofParameters?

In setup(), such as:

MAX_DEPTH and MAX_DRAW are 2 ofParameter of int and float.

    MAX_DEPTH.newListener([this](int &v) { drawAlgo(); });
    MAX_DRAW.newListener([this](float &v) { drawAlgo(); });

But these never get called.

  1. define the ofParameter’s, name, min, max…etc
  2. add all of them to an ofParameterGroup.
  3. add the listener function and define the callback, checking what’s the name of the ofParameter that trigged the callback.
  4. remove the listener on exit().

That’s an easy way because you can handle all the parameters grouped.
Also you can store/recall all the grouped parameters states/values easy with de/serialization to an .xml file.
But you can also can make a listener for any single parameter, like you can see on: /openFrameworks/examples/gui/guiExample

ofApp.h

	ofParameterGroup parameters;
	ofParameter<float> parameter1;
	ofParameter<int> parameter2;
	void Changed_parameters(ofAbstractParameter &e);
	ofxPanel gui_panel;
ofApp.cpp

void ofApp::setup(){
    parameter1.set("parameter1 Name", 0.0f, 0.0f, 1.f);
    parameter2.set("parameter2 Name", 0, 0, 10);

	parameters.setName("group of parameters");
	parameters.add(parameter1);
	parameters.add(parameter2);

    gui_panel.setup("myPanel");
    gui_panel.add(parameters);

    ofAddListener(parameters.parameterChangedE(), this, &ofApp::Changed_parameters);

}

void ofApp::Changed_parameters(ofAbstractParameter &e) {
        string WIDGET_name = e.getName();

        ofLogNotice() << "a parameter from group has changed : " << WIDGET_name << ": " << e;

        if (WIDGET_name == "parameter1 Name")
        {
            // re-check if type is float as expected (not required)
            if(e.type() == typeid(ofParameter<float>).name() )
            {
                ofParameter<float> p = e.cast<float>();
                ofLogNotice() << "parameter1 type is a float with value: " <<  p.get();
            }
            // ofLogNotice() << "parameter1 = " <<  parameter1;
        }
        else if (WIDGET_name == "parameter2 Name")
        {
            ofLogNotice() << "parameter2 = " <<  parameter2;
        }
}

void ofApp::exit{
 ofRemoveListener(parameters.parameterChangedE(), this, &ofApp::Changed_parameters);
}
1 Like

You need to store it somewhere, you can see this thread, where Arturo explains it:

Eduard.

… it seems that lambda callbacks are more modern, better performance and no need to unsubscribe/destroy (?)

But ofParameterGroup do not have .newListener method, so we need to create a callback method for each parameter to use this lambdas callbacks?

This kind of grouped params callback:

void ofApp::Changed_parameters(ofAbstractParameter &e) {
        string name = e.getName();
        ofLogNotice() << name << ": " << e;
        if (name == "parameter1 Name")
        { }
        else if (name == "parameter2 Name")
        { }
        else if (name == "parameter3 Name")
        { }
}

are very handy to me, but I am having many of problems, like recursive crashes in some scenarios (when some params changed inside the callback or when loading/serialize settings etc…)

Should I stop using this grouped callback?
it’s recommended to use a lambda callback for each parameter always?

Ho has the .newListener method are the ofEvents. So you can do ofParameterGroup::parameterChangedE().newListener(… ).
ofParameter implements a .newListener method that adds the passed lambda into newListener method of the internal event. HERE THE CODE.

I don’t know if parameter callback is recomended in favour to grouped callback.
In my personal cases I use callbacks for each parameter so I can use the power of capture variables in lambda functions. As in here.

I have not seen much issues with parameter callbacks if you stick to the main thread. I remember that playing with different threads and callbacks gave me weird crashes in parameter listeners.

1 Like