I’m adding a UIMage to the WidgetTree RootWidget for a custom cursor class using UUserWidget. While this works and the design view show the image the Hierarchy view that lists the widgets continues to show the Canvas panel that is automatically added.
In the UMGEditor the hierarcy view is managed by a WidgetTreeView but I can’t tell how to tell it to update it’s view of the items in the UUserWidget.
Sorry to revive the thread after so long, but I stumbled upon it when I was looking for an answer for the same issue so it might be worth finally answering it after I sorted it out for myself.
It was easier to understand after reading this article from Ben’s UI:
Basically I believe in order for the changes to be propagated correctly you will need to do several things:
Get a reference to the Widget Blueprint as this is what you will need to be modifying:
To propagate all of the changes so they do not get lost you will need to mark all of the assets that have been modified as “dirty” using Modify() and mark the blueprint as structurally modified:
I have encounter an issue however when i call FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified. This causes a hard crash about a second later during widget repaint from ChildrenBase.h -> Debug_TestDestroyTag() with the message: “The FChildren is destroyed. You probably have 1 widget owned by 2 different FChildren.”
The crash happens regardless of whether I actually make modifications or just set the flags.
I’ve not been able to determine where/why. Did you encounter anything similar or have any ideas?
Update: Added example code that works correctly on a custom User Widget, but causes a crash when that custom user widget is included in another custom user widget via the other widgets named slot.
void UDevHelpBPFL::RemoveChild_Editor(UWidget* parent, UWidget* child) {
#if WITH_EDITOR
//https://forums.unrealengine.com/t/c-adding-widget-to-widgettree-doesnt-update-hierarchy-view-in-editor/361258/13
//https://unreal-garden.com/tutorials/build-widgets-in-editor/
if (IsValid(parent) && IsValid(child)) {
//Walk the hirearchy till reaching the root User Widget
UObject* root = parent;
while (true) {
UObject* currentWidgetTree = root->GetOuter();
UObject* treeOuter = currentWidgetTree ? currentWidgetTree->GetOuter() : nullptr;
if (treeOuter && treeOuter->IsA<UUserWidget>()) {
root = treeOuter;
} else {
// Reached top level widget.
break;
}
}
UUserWidget* rootWidget = Cast<UUserWidget>(root);
if (rootWidget == nullptr) {
return;
}
UWidgetBlueprintGeneratedClass* wbpClass = Cast<UWidgetBlueprintGeneratedClass>(rootWidget->GetClass());
UWidgetBlueprint* asset = Cast<UWidgetBlueprint>(wbpClass->GetPackage()->FindAssetInPackage());
//Gain reference to the tree root and flag it as modified.
UWidget* treePanelRoot = asset->WidgetTree->FindWidget(root->GetFName());
if (treePanelRoot != nullptr) {
treePanelRoot->Modify();
}
//Gain reference to the child in the tree and modigy it.
UWidget* treePanelChild = asset->WidgetTree->FindWidget(child->GetFName());
if (treePanelChild != nullptr) {
treePanelChild->RemoveFromParent();
treePanelChild->Modify();
}
//Mark asset as having been modified including structurally
asset->Modify();
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(asset);
}
#endif
}