ofParameter linked/listening to another

In my app I would like to be able to linke values of arbitrary parameters.
For this I plan to change all of my member variables to ofParameter.

I understand, that I can add listener methods to them. Like this

myObject.h

[…]
ofParameter<unsigned char> myParameter;

unsigned char getMyParameter();
void setMyParameter(unsigned char value);
void setMyParameterFromListener(unsigned char & value);
[…]

and then add the function as a listener

test1 = new myObject();
test2 = new myObject();

test1->myParameter.addListener(test2, &myObject::setMyParameterFromListener);
test1->setValue(128);

ofLogNotice() << "test1: " << (int)test1->getValue();
ofLogNotice() << "test2: " << (int)test2->getValue();

// [notice ] test1: 128
// [notice ] test2: 128

This way, however I would need to add a method for each and every parameter in each and every class I write :worried:

Is there a direct way to link the value of two ofParameters (of the same type)?

Something like this would be perfect:

test1->myParameter.addListener(test3->myParameter, &ofParameter<unsigned char>::set);

Or even better

test1->myParameter.addListener(test3->myParameter)

Just a question here. Do you really want to store multiple times a variable and automte updates on change? updating could lead to an endless cyclic feedback… isn’t possible in your application to have one single storage and get a pointer to it in as many objects as you want?

this could work if we allowed listeners that got a parameter by value but we don’t have support for that syntax yet. I’ve thought about this some times but never get to really add it. Probably for next version.

test1->myParameter.addListener(test3->myParameter, &ofParameter<unsigned char>::set);

what you can do instead is use lambda functions as listeners like:

test1->myParameter.addListener([](unsigned char &v){ test3->myParameter.set(v); });
1 Like

@Jordi
I would like to make links between objects at runtime. Something like the AE pick whip tool.
This way one objects parameter could control parameters of another object. Think of „Animated x-value of A changes transparency of B“.

@arturo
I am not very familiar with Lambda functions so please excuse if I don’t understand above statement ceompletely.
I get two errors

Lambda issue
ofApp.cpp:19:58: 'this' cannot be implicitly captured in this context

Semantic issue
ofParameter.h:434:7: Candidate function template not viable: requires at least 2 arguments, but 1 was provided

I guess the latter refers to the definition of ofParameter::addListener which excpects not only a callback function but also a class it should invoke it on.

The first I don’t quite understand. maybe it complains because the Lambda function doesn’t have test3 in it’s scope?!

oh you are right this will only work using the nightlies but not with 0.9.8. The correct syntax though would be:

test1->myParameter.addListener([this](unsigned char &v){ test3->myParameter.set(v); });

so you can use this from inside the lambda function (to be able to access test3)

That solves the missing reference to test3, thanks :slight_smile:
But still missing the listener class

ofApp.cpp:20:24: No matching member function for call to 'addListener'
ofParameter.h:434:7: Candidate function template not viable: requires at least 2 arguments, but 1 was provided

yes, as i said this won’t work with openframeworks 0.9.8 only using the niglhly builds or openframeworks from github

I downloaded and tried both, a nightly build and the master from github.
Still in ofParameter.h I can only find a method with the signature

void addListener(ListenerClass * listener, ListenerMethod method, int prio=OF_EVENT_ORDER_AFTER_APP)

which expects a listener and a method.
Sorry, but I am confused on how your code line could work as it’s only providing the method?! :confused:

oh yeah sorry i thought you were using events rather than parameters. with ofParameter if you want to use lambda functions you need to use newListener instead of addListener like:

ofEventListener listener = test1->myParameter.newListener([this](unsigned char &v){ test3->myParameter.set(v); });

where listener removes the listener whenever it’s deleted so you need to keep it around until you want that listener to keep working. for example by keeping it as an instance variable next to test1

Thanks, that works :slight_smile:
Just for the record, this only works on latest builds. No 0.9.8.

hey @arturo, hey all:

I am trying to “link” two color parameters to be able to change from two differents ways:

  1. from a color picker or 2. from a random method.
    As mentioned above, I’ll like to avoid loopback changes, and reduce callbacks too…

I tried the above pattern:

ofxColorManager.h
ofParameter<ofFloatColor> color_picked;
ofParameter<ofFloatColor> color_randomized;
ofxColorManager.cpp :: setup()
color_picked.addListener([this](ofFloatColor &v){ color_randomized.set(v); });

but I get:

Error:(153, 18) no matching member function for call to ‘addListener’

This other way (same than gui examples) is working but I am not sure can be problematic in some way. (Maybe i’ll need a bool to disable the listener when color_randomized -> color_picked, and use another listener.)

ofxColorManager.h
void Changed_color(ofFloatColor & color);

ofxColorManager.cpp :: setup()
color_picked.addListener(this,&ofxColorManager::Changed_color);

void ofxColorManager::Changed_color(ofFloatColor & color)
{
    ofLogNotice("ofxColorManager") << "Changed_color (by picker)" << ofToString(color);
    color_randomized.set(color);
}

Ideally, I would like to add hue/sat/brgt sliders to my gui, to modify/receive the color(s) too, so I wouldn’t like to fall into callbacks ‘overflow’/loopback…

The problem is that you use .addListener method, and you should be using .newListener method, also you have to save the listener into a variable, see last post of Arturo in this thread, or this blog post about new event system in OF0.10: https://blog.openframeworks.cc/post/173223240829/events

Eduard

2 Likes