ValueTree: Getting all child objects the ValueTree object

I went through the ValueTree intro tutorial last night and successfully implemented a valuetree for setting parameters in different locations on my app but I have a question:

What’s the best or most typical way of setting up a ValueTree so that child objects have access to it?

There is an example in the tutorial of setting up a class as a ValueTree::Listener and a ValueTree is passed to the constructor so that the child object now has ValueTree access:

struct ExampleListener  : public ValueTree::Listener
{
ExampleListener (ValueTree v)
    : tree (v)
{
    tree.addListener (this);
}
 
ValueTree tree;
};

Is this the way that you would most often get child objects access to the apps common ValueTree, just by passing and initializing in the constructor? If it is, it seems like it could be quite a bit of boiler plate, so I wonder if there is a different way of giving access to the ValueTree.

Thanks!

I’ve been using a similar model so far, having the main object type contain its own valuetree. But little by little, this has become more and more of a pain - since sometimes I want to manipulate the data without changing the object or vice versa. So now I’m slowly migrating all tree-based functionality to a manager-type class, which also has a Component::Listener to get all necessary information and updates the ValueTree data structure.

Meanwhile, the number one thing that has helped me, is having a ReferenceCountedPtr to the object itself as a ValueTree property. This has been really useful because anytime I have the tree, I can pull the object out. And trees are easier to navigate than dynamic_cast'ing components because of the methods and their easy type-checking. For now, only my main component class owns its own ValueTree, all the other lower-down classes don’t - so I use that property (and methods like getChildWithProperty("object", objectPtr) to navigate between the two.

The transfer I’m doing is just moving a level up so that I effectively avoid doing what’s in the example you gave for my main object class. I think a ComponentListener along with the trees having a pointer property to their component seems like a better structure, it’s working well for me so far.

Let me know if there’s something about this model that doesn’t work for you. I’ve gone through a few iterations with different ideas so I may still be able to pitch in.

Good luck!

2 Likes

So when you say you use a ReferenceCounted Ptr do you mean it’s like a globally available pointer to the ValueTree but it’s own by the main component? Sorry if I’m slow on the uptake here because I’m not so seasoned with Juce.

The other way around - a RefCntPtr belonging to the ValueTree pointing to the object.

At the minute in my new implementation I’m finding it inconvenient not to have a reference the other way around. I’m considering other options, pointing from object to tree. But searching the tree based on that same Ptr, comparing to the object, works

1 Like

Gotcha. I’ll have to take a look at that. I’m curious to know what other people choose to do. Do you know of some open source projects to look at that really take advantage of the ValueTree? I’ve checked some other repositories like Matt Tytels Helm synth but he seems to have opted for other methods of effecting change to child objects.

I use a system wide dual ValueTree system, where I have a persistent ValueTree which any changes to are saved to the apps properties file, and a runtime ValueTree. These VT’s are passed down through any objects which need access to the VT system. And I have classes that will ‘wrap’ VT’s, and provide an API to interact with the underlying data (getters, setters, and callbacks), for a given specific data model. I write ValueTree code once when I write the wrapper, and from then on I use the wrapper interface. As an example, I have GuiProperties VT, which is a branch of the persistent tree, so if there is a piece of code which wants to have access to the GuiProperties, it would look something like this:

MyClass::init (ValueTree persistentVT, ValueTree runtimeVT)
{
    // assuming MyClass has a member GuiProperties guiProperties
    guiProperties.wrap (persistentVT); // the GuiProperties VT was added to the persistentVT at startup
    guiProperties.onOrientationChange = [this] () { handleOrientationChange(); };
    guiProperties.enableCallbacks (true);

    handleOrientationChange();
}

void MyClass::handleOrientationChange()
{
    switch (guiProperties.getOrientation())
    {
        case GuiProperties::orientationDesktop:
        {
        }
        break;
        case GuiProperties::orientation::Landscape:
        {
        }
        break;
        // etc
    }
}
3 Likes

Interesting idea. And when you pass them down to other objects do you just pass the VT through the constructor? I appreciate all the input, everyone. :slight_smile: I’m slowly figuring stuff out.

Sometimes I pass it through the ctor, but I have generally settled on the form in my example above, MyClass::init (ValueTree persistentVT, ValueTree runtimeVT). Either way works. For me, I like that I have hidden the ValueTreeness and can focus on an API.