Accessing ValueTree from child component - strange behaviour


#1

I am trying to access a ValueTree strored in an object belonging to my MainContentComponent, from a component (InterfaceComponent) nested inside it.  

Within the MainContentComponent I have an instance of a class (say MyClass) which contains a ValueTree,

 

I've declared a pointer in the InterfaceComponent as: 

MainContentComponent* main;

In the InterfaceComponent constructor I've defined:

main = static_cast<MainContentComponent*>(getTopLevelComponent());

However, if I try and access the ValueTree using the pointer

ValueTree valueTree = main->myClass.valueTree;
log->writeToLog("numChildren:"+String(valueTree.getNumChildren()));

It seems to not be initialised,  even though it passes the isValid() function - getNumChildren() returns a large random value (e.g. 27888).

I've just rearranged some code and it looks like the InterfaceComponent constructor is called before the MainContentComponent one, so that the object I am trying to share has not been initialised when the nested Component is trying to access it. I would expect the ValueTree to not be valid in this case.

Perhaps I am going about this a strange way, basically just want a way of sharing data across components. 


#2

That wont fly, at least not elegantly

Use composition

childComponent.setValueTree(ValueTree* treeToSet);

and then just use that pointer

Dont forget to initialize properly either to the right value tree in the constructor, or to a nullptr if you are putting it later


#3

Thanks, I have changed it around so that I am setting it via

getChildComponent(0)->setValueTree(&myClass.valueTree)

This is working. I can test that the ValueTree is as it should be from the setValueTree function of the childComponent (InterfaceComponent).

The InterfaceComponent has a pointer, ValueTree* valueTree, which is set to nullptr at the constructor:

InterfaceComponent::InterfaceComponent () : valueTree(nullptr)  

InterfaceComponent also inherits Value::Listener, to update a GUI element with incoming values.

For a reason I cannot work out, the InterfaceComponent::valueChanged override function says the valueTree is nullptr, even though the log output says it has been previously initialised by the setValueTree function (which shows correct output).     

 

 


#4

Don't use pointers to ValueTrees!

They have value semantics, and although you might sometimes want to pass them by reference, there's almost never a good reason to take a pointer to one.


#5

Ok, thanks, I did try without and was getting similar behaviour, i.e. the ValueTree having random values when called from the valueChanged function... I'll take out the pointer and report back.


#6

OK - I have now taken out the pointer to the ValueTree, but the problem remains - the valueChanged function gets an invalid (empty) ValueTree where it has been set and tested to be valid in the setValueTree function, which is called before the valueChanged function as I can see in the log output.. 


#7

Code for clarity: 

InterfaceComponent constructor

InterfaceComponent::InterfaceComponent () : valueTree(ValueTree()) {...}

ValueTree declaration, InterfaceComponent.h 

ValueTree valueTree;


InterfaceComponent.cpp

void InterfaceComponent::setValueTree (ValueTree& treeToSet)
{

    valueTree = treeToSet;

    log->writeToLog("Interface.valueTree.numChildren:"+String(valueTree.getNumChildren()));

}

void InterfaceComponent::valueChanged(juce::Value &value)

{

    if (value.refersToSameSourceAs(currentValue))

    {

        ...
            log->writeToLog("Interface.valueTree.valueChanged.numChildren:"+String(valueTree.getNumChildren()));

            if (valueTree.isValid())
            {
                ...
            }
            else
            {
                log->writeToLog ("noteTree invalid");
            }

    }

}


From MainComponent.cpp constructor:

    static_cast<InterfaceComponent*>(getChildComponent(0)->setValueTree(myClass.noteTree);

Output from console log:

Interface.noteTree.numChildren:55

noteTree(MainComponent).numChildren:55

Interface.noteTree.valueChanged.numChildren:0

noteTree invalid

Interface.noteTree.valueChanged.numChildren:0

noteTree invalid  ...

 


#8

Sorry guys, I oversimplified the code I posted, and actually the problem was a nullptr to the InterfaceComponent, as it is nested inside a TabbedComponent, and I wasn't checking for nullptr before calling the method  - I changed static_cast to dynamic and followed how its done in Introjucer, using jassert to make sure, and then discovered the getTabContentComponent function which was what I needed to get at the necessary component. 

Hope I have not cluttered the forum with my debugging,  Jules feel free to delete thread in case it confuses people searching in future...