Question about custom ListBox components


#1

I’m using a custom Label component for my ListBox because I want to be able to double-click the ListBox items and rename them. Everything is working, except that I’m getting memory leaks from the ListBoxModel::refreshComponentForRow(int row, bool selected, Component* existingComponent) method.

Here’s my code:

So basically, if the method provides nullptr I create a new object, and if not I alter the provided component’s properties and return it. Am I missing something? For some reason, if I add more rows past the 11th row it starts leaking. I assume it has to do with the fact that my ListBox is only tall enough to display 11 rows at once.

I’m not really sure where this is coming from, and stepping through the code hasn’t revealed anything so far.
I figure that I might be going about this the wrong way.


#2

The hint is in the docs:
https://www.juce.com/doc/classListBoxModel#af049aa731e43557c107b1285ca7e3d88

If you don’t need a custom component for the specified row, then return nullptr. (Bear in mind that even if you’re not creating a new component, you may still need to delete existingComponentToUpdate if it’s non-null).

So I guess in line 16 if you have controller == nullptr, you need to dispose eventually the existing component.


#3

Yes, I saw that in the docs but I don’t understand when I would need to delete an existing component. Line 16 is irrelevant to this, I should have removed it.

What I also don’t understand is why it starts leaking starting at the 12th row that is created. When I add a 12th row, this method passes nullptr, not an existing component, at which point I create a new component which causes the leaking. Shouldn’t it pass a component in that case and not nullptr?

I don’t understand what the ListBox automatically deletes and what it doesn’t. It says in the docs:

The component that your method returns will be deleted by the ListBox when it is no longer needed.

So I guess I’m just confused in general about when I need to delete something manually that’s used by the ListBox.


#4

Sorry, then I’m as clueless as you, but a side note, probably unrelated:
better use a dynamic_cast rather than the C-style cast:

PageListBoxRowComponent* p = (PageListBoxRowComponent*)existingComponent;

would become:

PageListBoxRowComponent* p = dynamic_cast<PageListBoxRowComponent*> (existingComponent);

and now you can check, if the existingComponent is of type PageListBoxRowComponent (otherwise it’s nullptr). That way you can replace it. But I don’t know, if that leads anywhere.

Good luck


#5

Thanks for the tip. It didn’t help but I should be using dynamic_casts in general.

I confirmed that past Row 11, the ListBox is not automatically deleting these rows for some reason. For now I found a bandaid solution by hanging onto those ptrs and deleting them manually, but I’ll have to investigate more to figure out if it’s a bug with Juce or something wrong I’m doing.

I think it may be a bug with having a ListBox inside of a ViewPort, since this allows you to have more rows in the ListBox than can be displayed.


#6

Hmmm… we use this quite often internally in JUCE and we don’t see memory leaks. See for example juce_FileListComponent.cpp:229 or juce_TableListBox.cpp:385. It must be something else your doing. Not sure if the extra ViewPort has anything to do with this, that would be an interesting test.