How to Notify Parent Data Structure When A Child Component Has Been Deleted?

I currently am creating a custom Component (x). The Component has a button that when pressed, adds a new Component (y) on the screen that is owned and managed by the main Component (x). You can hit this button many times and add more of these child Components, which are stored in a std::vector in the main Component (x). The child Components are laid out in a Flexbox that is regenerated every time a new child is added. Each of the child Components have a remove button. The goal is to be able to remove a child component by clicking its remove button, but I need to be able to tell the parent structure (x) that this deletion has occurred.

Currently, the vector in the main Component uses SafePointers that point to the children and the children call delete this whenever the remove button on them is pressed. This will then cause the associated SafePointer in the vector to become null.

The issue is that I don’t know how to tell the main Component (x) about this deletion, so it doesn’t know to recall the layout function, which leaves the UI looking as if there is a missing widget. I can’t use findParentComponentOfClass<>() inside of the remove button code to call the relayout function in the parent structure, because the remove code deletes the object itself, making it no longer valid, thus not being able to make execute any code after.

I found componentBeingDeleted (Component &component), so I thought I’d try adding a listener to the components being deleted, so I could call the relayout function, but what I’ve found is that it doesn’t execute after the deletion every time, it sometimes executes before the deletion finishes, so I can’t reliably use that.

I’ve hacked a solution that sort of works, but isn’t ideal. The solution I’m currently using is to not delete the child when the remove button is clicked, but to set a Boolean variable that will be used in the parent structure. Then, after, in the remove code, call the relayout of the parent structure using findParentComponentOfClass<>(). This leaves a bunch of null pointing pointers in the vector, which are then cleaned out whenever the button to add new children is clicked. This isn’t ideal. I would really like for the parent object to know whenever a child is deleted, so I can remove it from the vector and relayout the remaining children.

Does anyone have any suggestions for this type of thing?

That’s a classic dilemma… I usually solve that with a method in the parent called deleteChild (Component*), and I call this method using MessageManager::callAsync(). That way your click can finish and the deleteChild() can do the deletion and trigger a layout update…

I know that this sort of design is all over the place, I just didn’t know how to tackle it in JUCE or how to even tackle it in general. Thanks for the suggestion, I’ll given this a try.

I guess I will have to re-work my parent structure to keep track of the children so that it somehow knows which button belongs to which child. I was calling delete this in the child components, so I never had to know which button belonged to which child.

I guess I could store the Childs location in the vector in each child when they are added, then send that information back when the remove button is clicked.

Edit:

Oh, I missed the part where you are passing in a pointer to the component when you call the deleteChild() method. Then you can just cycle through the vector and find it.

I would keep the delete button in the child, but have it make the call to the parent (by having a back link reference)

void buttonClicked (Button*) override
{
    MessageManager::callAsync ([this] { parent.deleteChild (this); });
}

// parent:
void deleteChild (Component* child)
{
    children.removeObject (child);
    resized();  // or other means to update your layout
}

EDIT: yes, that’s OwnedArray, but similar for vector…

1 Like

I have no reason for having a vector over another JUCE-specific data structure. I might switch it if it makes more sense.

Thanks a lot Danial, I always appreciate your help.

1 Like

Does the OwnedArray delete the object when it is removed from the array?

Yes, that is the point of OwnedArray<T>… it is basically a std::vector<std::unique_ptr<T>>

1 Like

Just ripped out my old mechanism and implemented this… it seems to be working perfectly. Thanks a TON again!

Hmm, maybe I’m missing something/joining the conversation too late, but in your “remove” button callback, couldn’t you simply:

  1. remove the child Component from its parent via removeChildComponent()
  2. call the parent re-layouting code
  3. delete the child Component

?