TreeView and createItemComponent request(or help!)


#1

I've got a treeview with custom components.  State has changed and I need to re-create the components(not just repaint).  I had hoped treeHasChanged would call createItemComponent again(for the visible items).

 

But it doesn't seem to.  Is there a way to do what I want? (Other than tearing down the rootItem and rebuilding it so that the uid is remade?)


#2

TreeViewItem::treeHasChanged() is the thing to call, that should give you a chance to update the components, right?


#3

Hi Jules.  It doesn't.   (Again, custom component created in the treeviewitem.). Well, let me put it this way, the visible ones don't get called, the ones off screen do get called.  I think table view has a refreshComponent method? A way to refresh or create a component.

 

it has to do with the uid in the tree view item I believe. It gets found in its OwnedArray and used so doesn't bother creating a new component.

ive tried to see if there's a workaround, but i can't see it.  Even if I iterate over the treeviewitems I can't get the underlying custom component.


#4

Hello! It's not entirely clear what the issue is here.

Could you give me a more concrete example of what you'd like / what doesn't seem to be working? If you could do it in code that I checkout here, that'd be even better.

Regards,

Joshua


#5

Hi Joshua... I have a treeview, filled with TreeViewItems.  This subclass of TreeViewItem let's call ServerTreeViewItem

 

It has overriden - Component * createItemComponent()

Let's call this ServerCustomComponent

 

Everything works great... I've got items visible.  Now something has happened... state has changed, and the ServerCustomComponent's needs to be redrawn/refreshed, told this new state.  I've been passing in the state when I createItemComponent and new ServerCustomComponent(state);

 

Logically I would think calling treeHasChanged() would mark all those custom components as needing to be re-created.  It doesn't.

It also seems different to how I think a table list box works, which can pass in a component to update, or null if it needs a new one.

 

In juce_Treeview there's updateComponents, which is called when treeHasChanged() is called...  my comments added... might be clearer that way....

for (int i = items.size(); --i >= 0;)

            items.getUnchecked(i)->shouldKeep = false;

        {

            TreeViewItem* item = owner.rootItem;

            int y = (item != nullptr && ! owner.rootItemVisible) ? -item->itemHeight : 0;


            while (item != nullptr && y < visibleBottom)

            {

                y += item->itemHeight;


                if (y >= visibleTop) 

                {

                    if (RowItem* const ri = findItem (item->uid)) // ITEM IS FOUND BECAUSE ITS VISIBLE, maybe it needs to be if (!refereshAllComponents && RowItem* const ri = findItem(item->uid))  and pass refreshAllComponents as a parameter to updateComponents?  Its not as elegant as how the tableview works but still...

                    {
// Component is found and is used as is... never having a chance to be updated...

                        ri->shouldKeep = true;

                    }

                    else if (Component* const comp = item->createItemComponent())

                    {

                        items.add (new RowItem (item, comp, item->uid));

                        addAndMakeVisible (comp);

                    }

                }


                item = item->getNextVisibleItem (true);

            }

        }

 

 

If it was safe(I know its not though)... to keep a pointer to the custom component inside my TreeViewItem subclass, I could simply update it myself.  But there doesn't seem to be anyway for me to get at the current OwnedArray of custom components myself...


#6

How about this?  An explicit clearCustomComponents() method in the TreeView

 

diff --git a/modules/juce_gui_basics/widgets/juce_TreeView.h b/modules/juce_gui_basics/widgets/juce_TreeView.h

index 74de758..e9773ed 100644

--- a/modules/juce_gui_basics/widgets/juce_TreeView.h

+++ b/modules/juce_gui_basics/widgets/juce_TreeView.h

@@ -831,6 +831,13 @@ public:

     void restoreOpennessState (const XmlElement& newState,

                                bool restoreStoredSelection);


+    ^M

+    /** If you are using custom components and need them explicitly recreated, calling this^M

+     will remove them(deleting them) and then call a treeHasChanged()^M

+     ^M

+     */^M

+    void clearCustomComponents() noexcept;^M

+    ^M

     //==============================================================================

     /** A set of colour IDs to use to change the colour of various aspects of the treeview.

 

And...

 

diff --git a/modules/juce_gui_basics/widgets/juce_TreeView.cpp b/modules/juce_gui_basics/widgets/juce_TreeView.cpp

index e78eb34..0af3285 100644

--- a/modules/juce_gui_basics/widgets/juce_TreeView.cpp

+++ b/modules/juce_gui_basics/widgets/juce_TreeView.cpp

@@ -168,7 +168,11 @@ public:


         return nullptr;

     }

+    void clearCustomComponents()^M

+    {^M

+        items.clear();^M


+    }^M

     void updateComponents()

     {

         const int visibleTop = -getY();

@@ -845,6 +849,12 @@ void TreeView::itemsChanged() noexcept

     viewport->getContentComp()->triggerAsyncUpdate();

 }


+void TreeView::clearCustomComponents() noexcept^M

+{^M

+    viewport->getContentComp()->clearCustomComponents();^M

+    itemsChanged();^M

+}^M

+^M

 void TreeView::recalculateIfNeeded()

 {

     if (needsRecalculating)

 

Seems harmless enough... I did try to integrate it into treeHasChanged, but that's called a lot internally, and was just clearing the custom components when they didn't need it.

 

The other approach, although more heavy handed would be to reset the uid for the treeview and all its children, but even that would generate a lot of un-necessary creation of components.

 

tnx for your consideration!


#7

Hello!

Thanks for the explanation. My worry here is that you'd end up in an infinite loop as follows:

  1. tree has changed
  2. clear components
  3. add new components
  4. tree has changed again! GOTO 1

...and so on ad-infinium.


#8

That’s why I made it an explicit call and not part of treeHasChanged