UMG: Which is the best way to change the order of box children at runtime?


I would like to know which is the best way (in your opinion) to change the order of the children widgets contained in a vertical/horizontal box container in UMG. For example, imagine that you have a vertical box with two widgets inside, the top one and the bottom one, and that in a certain event you want to switch their order in the box (i.e. make the top widget occupy the position where the bottom one was, and viceversa).

I’ve checked similar cases in the forums or AnswerHub in which it was recommended to delete the widgets from the container (e.g. using the “Remove Child” function called for the container or “Remove From Parent” function called for the children widgets) and then add them back in the new order, but this doesn’t work with the same widget reference that was removed, since it was apparently removed not only from the parent, but cleared out from memory. What I’ve seen in those older threads is that they remove the widgets, create new instances and then add them to the container in the new order.

I would like to know if there’s a better way to do this, e.g. one that recycles the old widgets instead of 1) deleting them, 2) creating new instances of them (basically clones) and 3) adding them in the desired order. It seems to be a bit of a waste of memory.

Thank you.

First let me say that I also use a full rebuild of the Box. I have the Widget bound to certain events, so when the data updates, the box recreates all its children. If you placed your data well, you should be able to easily recreate all widgets (that amongst other things requires that the Box Elements do NOT store the data as owner but only represent it).

There are ways to solve this actually. But you likely won’t be able to do that in Blueprints.
The widget types you are referring to are PanelWidgets (that can contain children). There is a C++ method, which is not exposed to BP which is called ReplaceChildAt, where you can replace a child at a specific index with another one (old one gets deleted). This could be one step, either rebuild the UMG Module with exposing this method to blueprints, or create an own User Widget that wraps this method (in C++ ofc).

Further, there are additional methods which are named InsertChildAt and ShiftChild which is what you need I guess (not exposed to BP). The problem there is that they are only compiled if you build with editor and this would again require rebuilding the UMG Module to change.

The last solution is requesting the array of PanelSlots with GetSlots() (C++ only). There you can obtain pointers to the slots. The array is constant and you can’t add or remove or change the slot pointers itself (unless using const_cast which is to avoid), but you can access the particular slots and set the Content (UPanelSlot::Content) which is your widget. Then you have to update the PanelSlot of your Widget (UWidget::PanelSlot). I don’t know if there is any more involved like requesting update etc. in the PanelWidget, but you will have to find out.

So unless you want to cope with these solutions I suggest fully rebuilding the Widgets.

Thank you, rebuilding the widgets is indeed straightforward if they are kept simple. ShiftChild seems to be the most memory-efficient solution for the case, but since it requires to modify the UMG module each time the engine is updated, I think that I’ll stick to widget rebuilding by now, since currently I only need the order switch for a couple of small widgets.

How do you go about getting a list of child widgets to rebuild from? Got an example?

Code Example in studio !

I am actually trying all of Your solutions:

  1. These with #WITH_EDITOR do work. But since no shipping - can not use them.
  2. ReplaceChildAt() - do not work properly. Swap occurs, but widget wont become visible, even though his Visibility is HitTestInvisible. RebuildWidget(), InvalidateLayoutAndVolatility() do not help. I’ve found no way to make this swapped widget actually render.

So any thoughs ony this anyone ?

1 Like