Using pure C++ UUserWidget inside of another BP widget in UMG editor

How to create UUserWidget and populate it with widgets in C++?
For example, create UUserWidget, then create and add Text Box to it

I’ve tried to WidgetTree->CosntructWidget and assigning it to WidgetTree->RootWidget inside NativeOnInitialized/NativeConstruct/NativePreConstruct, like so:

// .h
UCLASS()
class PURECPPWIDGET_API UMyUserWidget : public UUserWidget
{
	GENERATED_BODY()

public:
	UCanvasPanel* CanvasPanel;

private:
	void NativeOnInitialized() override;
	void NativeConstruct() override;
	void NativePreConstruct() override;

	void CreateWidgets();
};

// .cpp
void UMyUserWidget::NativeOnInitialized()
{
	UE_LOG(LogTemp, Warning, TEXT("UMyUserWidget::NativeOnInitialized before"));
	Super::NativeOnInitialized();

	CreateWidgets();
}

void UMyUserWidget::NativeConstruct()
{
	UE_LOG(LogTemp, Warning, TEXT("UMyUserWidget::NativeCosntruct"));
	Super::NativeConstruct();
}

void UMyUserWidget::NativePreConstruct()
{
	UE_LOG(LogTemp, Warning, TEXT("UMyUserWidget::NativePreConstruct"));
	Super::NativePreConstruct();
}

void UMyUserWidget::CreateWidgets()
{
	UE_LOG(LogTemp, Warning, TEXT("UMyUserWidget::CreateWidgets before"));

	CanvasPanel = WidgetTree->ConstructWidget<UCanvasPanel>(UCanvasPanel::StaticClass());
	if (!CanvasPanel)
		return;

	auto textBlock = WidgetTree->ConstructWidget<UTextBlock>(UTextBlock::StaticClass());
	textBlock->SetText(FText::FromString("Hello World!"));
	CanvasPanel->AddChildToCanvas(textBlock);

        // WidgetTree->RootWidget = textBlock;
	WidgetTree->RootWidget = CanvasPanel;

	UE_LOG(LogTemp, Warning, TEXT("UMyUserWidget::CreateWidgets after"));
}

But when I add My User Widget in UMG editor, nothing is visible

I think a similar question has already been asked and answered in this thread.

Yeah, and I’ve tried the solution from there but it doesn’t work Create widget in pure C++ - #41 by isaac4096

I remember trying to do this a while back and gave up. The only thing I’ve seen since is trying to tell the editor that the widget hierarchy has been modified. You’ll need to call Modify() on every asset you’ve added and every parent in the hierarchy.

    UWidgetBlueprintGeneratedClass* wbpClass = Cast<UWidgetBlueprintGeneratedClass>(WidgetTree->RootWidget->GetClass());
    UWidgetBlueprint* asset = Cast<UWidgetBlueprint>(wbpClass->GetPackage()->FindAssetInPackage());

    asset->Modify();

    // Tell editor that blueprint has changed.
    FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(asset);

I have no clue if this will work but thought I’d mention it as it’s easy enough to try.

1 Like

I won’t lie, I should have checked that thread before suggesting it, as it doesn’t even have a proper answer to the OP’s problem. I just saw a post with 13 likes and was convinced it should work.
I found a site that seems to do what you’re asking. I tested it myself, and it seems to work (sort of).

1 Like

The correct way:

is to declare the widget in C++ using the UPROPERTY meta specifier “BindWidget” as I do in my framework:

Look for “BindWidget”

Ferrefy-Plugin-UI-Additions/UIAdditionsPlugin/Source/UIAdditionsPlugin/Public/UI/UserWidgets/DecisionDialog/DecisionDialogWidget.h at master · Seda145/Ferrefy-Plugin-UI-Additions · GitHub

Direct example:

    UPROPERTY(BlueprintReadOnly, Category = "Widgets", meta = (BindWidget))
        UTextBlock* TitleTextWidget = nullptr;

You then create a UserWidget based on this C++ UserWidget and open that in the widget editor. The widget designer will be notified that an inner widget is either optional or required (by name and widget type).

During runtime the C++ widget pointer will automatically be set to the inner widget the designer placed on the widget editor.

This makes it possible to write all the core logic in C++ while not yet having the design. The designer still has complete freedom to implement the widget tree’s layout.

I don’t know if the widget editor (or the UAsset) allows this, or should.

Of these only NativePreConstruct would run inside the editor window, and it could run multiple times conditionally as well. Afaik it runs every time the widget tree changes.

Something else:

Your header has a flaw:

public:
	UCanvasPanel* CanvasPanel;

problem 1:

UCanvasPanel is a UObject so it should be marked as UPROPERTY, as it is a property of your class. Not marking it UPROPERTY will cause it to be garbage collected incorrectly (nulling your pointer when it should not).

The garbage collector system builds a chain of UObjects referencing UObjects. If a UObject is not part of the main chain (not referenced properly (or not marked UPROPERTY when should)), it is garbage collected.

problem 2:
The pointer is not initialized as nullptr. This can lead to undefined behavior.

problem 3:
A category is missing for a blueprint accessible property. Afaik I’ve only seen FAB complain when you don’t add the category specifier to a UPROPERTY.

A best practice recommendation:

Mark the property as private or protected when possible. If required to directly access the property (either within that space or pubicly), write a getter method.

Fix:

protected:

UPROPERTY(BlueprintReadOnly, Category = "Widgets", meta = (BindWidget))
UCanvasPanel* MyCanvasPanel = nullptr;

Epic’s recommendation:

Since UE5 EPIC started to recommend using TObjectPtr over raw pointers, but it’s not a requirement. Not required by the engine, not by FAB, really just optional.

Why should I replace raw pointers with TObjectPtr?