ofParameterGroup best practices

Hello all, I’m trying to use ofParameterGroup to store values read from an xml file.

My problem is that I don’t know how to retrieve the ofParameter instance from an ofParameterGroup.
I can do

float v = properties.getFloat("opacity");

But how can I

ofParameter aProp = properties.get("opacity");

properties beeing an instance of ofParameterGroup.
I understand that ofParameter is a class template and so I can’t define a local aProp without giving it a type (float, int whatever). But is there any kind of typecasting what would allow me to get back an instance of ofParameter ?

Thanks in advance

you can do:

ofParameter<float> aProp = properties.getFloat("opacity");

But in that case it means that I ‘know’ the kind of inner type that ofParameter is storing…

How could I stay abstract from this ? I would like an Interpolator class to register ofParameters, then interpolate theirs values (no matter if they are float or int) using theirs overloaded operators (+= in that case).

Is it possible ?

Something more :

properties[pOpacity] = ofParameter <float>("opacity", 1.0f);

Crashes, because [] operator is intended to read ofParameterGroup content but not to write something in it.
So, adding an ofParameter to the ofParameterGroup must be done with add, then call getPosition(“opacity”), store the index value somewhere, then use it with the [] operator of ofParameterGroup. Quite tedious, unless I missed something…

My idea of using integer index is, obviously, speed. Getting the property from the group by string key can’t be as fast as integer key.

Any idea ??

Thanks !

not sure what you are trying to do but i usually use ofParameter like:

class SomeClass{
public:
    ofParameter<int> param1;
    ofParameter<float> param2;
    ofParameter<bool> param3;
    ofParameterGroup parameters;

    SomeClass(){
        parameters.add(param1.set("param1",0,0,10));
        parameters.add(param2.set("param2",0,0,10));
        parameters.add(param3.set("param3",false));
    }
}

class ofApp{
    void setup(){
        gui.add(object1.parameters);
        gui.add(object2.parameters);
        gui.load("settings.xml")
    }
    SomeClass object1;
    SomeClass object2;
}

then access the parameters through the specific variable not through the group the group is only used to save and load or pass to a gui or similar.

you can also not use a gui and instead group all the parameter groups in a parent group and load/save that through ofXml::serialize and deserialize.

2 Likes

Yeah, my posts need to be a little bit more clear :wink:

In fact, I want to use ofParameterGroup in a way totally unrelated with ofxGui… May be I’m following the wrong path.

I have properties in an xml file, then when I load the file, I create class instances. And instead of using plain float or int class members I thought to switch to ofParameter… Dunno, may be I’m over complicating things

as i said that example is valid if you are not using any gui, just change the gui with another ofParameterGroup. then you can load the whole hierarchy in one call by loading the top group. that’s of course if you know the hierarchy structure before hand if not then you’ll need to parse the xml anyway. at some point ofParameterGroup should be able to deserialized dynamically by having some kind of type indication in the file but that doesn’t work yet.

in any case something[index] when index doesn’t exist yet will usually crash in almost any other collection mostly when it’s a position based index.

Thanks Arturo, I’ve tried to investigate a little further…

Now I have a listener, listening for all the properties changed in a group :

void Media::propertyChange(ofAbstractParameter & parameter) 
{
ofLog() << parameter.getName() << " changed " << parameter;
}

But unfortunately, I don’t find the right syntax to type cast parameter to its float, int, bool value.

I’ve tried

ofParameter<float> prop = ofParameter<float>(parameter);

But I get compile time error “No matching conversion for functional-style cast from ‘ofAbstractParameter’ to ‘ofParameter’

And

ofParameter<float> prop = dynamic_cast<ofParameter<float> >(parameter);

Produces “‘ofParameter’ is not a reference or pointer

Okay, found the solution :smile:

float v = static_cast<ofParameter<float>& >(parameter);

or

ofParameter<float> prop = static_cast<ofParameter<float>& >(parameter);

you can also do:

ofParameter<float> prop = parameter.cast<float>();

which internally does the static cast you are using now.

So, huuuuu still fighting !! Sorry to bother you again with my problems but…

I try to deserialize an ofParameterGroup, which instance’s name is properties and I do a properties.setName(“properties”)

A foo.xml file is structured as

<medias>
 <media>
  <properties>
    <opacity>2</opacity>
    <filename>Gogol.ogg</filename>
 </properties>
 </media>
</medias>

This piece of code doesn’t retrieve the properties correctly

    properties.clear();
	properties.setSerializable(true);
	ofxXmlSettings settings;
	settings.loadFile("foo.xml");
	settings.pushTag("medias");
	settings.pushTag("media");
	settings.deserialize(properties);
	settings.popTag();
	settings.popTag();
	ofLog() << properties.toString();

I really don’t see what’s wrong with this code snippet…

Figured it out, reading OF source code -> ofXml.cpp, deserialize() method

The parameters must already exist in the group. The deserialize function doesn’t try to guess the parameters type (“2.something” being a float, 3 floats being an ofVector3, “true” being a bool, anything else being a string, and so on. Which would be very hazardous.

yes having that would be great but we should come up with an xml (or other serializations) format which also specify the types

Yes, would be very cool and (dunno but) the same format could be used for ofMesh file saving, instead of current ascii (don’t remember the name) format…

No matter, still still fighting. I did get ofParameterGroup deserialize to work, in a small sandbox test application.
But, when integrated in my “real” app, I get a strange behavior.
I’ve stepped into deserialize source code and found that :

  • The current tag is well handled, is tagPushed, ok
  • BUT, when deserialize goes recursive the name of the next parameter is not retrieved correctly. In fact it appears that my ofParameter had a “” name.

So I just checked this out :

	opacity = ofParameter <float>("opacity", 1.0f);
ofLog() << opacity.getName();

And guess what ? opacity.getName() returns an empty “” name.
I had to use .setName() on every ofParameter, and it works… Is it a bug ?

this was done on purpose cause the way ofParameter can be used as a value meant that being opacity and someparameter 2 ofParameter something like:

opacity = someparameter * 5;

would make opacity take the value of the someparameter * 5 but:

opacity = someparameter;

would make opacity be a reference to someslider which would be confusing. so if you want to set a parameter value and name you have to do:

opacity.set("opacity",1.0f);

and if you want to make it a reference to another ofParameter:

opacity.makeReferenceTo(someparameter);

there’s an example in gui/edgeCasesExample that shows all this weird cases

1 Like

Thanks Arturo, I’ll go that way… But I still don’t understand why the 1.0f value of the constructor is correctly taken in account, while the name is not…

In OF source code, ofParameter.h I can find this constructor

ofParameter(string name, ParameterType v);

If name is not used / has no effect, so why is there a constructor like this ?

it is used, if you do:

ofParameter opacity("opacity", 1.0f);

it works as you are expecting what it’s different that what you expect is how the = operator works in:

opacity = ofParameter <float>("opacity", 1.0f);

where the constructed parameter is not referenced or copied completely to opacity but instead only it’s value is copied

1 Like

Got it ! Thanks a lot !