Create widget in pure C++

You are too sensitive. You could be more comprehensive and gentle, you may forgot: at least that guy is willing to “waste” his time to Typing and ScreenShotting for you man.

And thanks for your code, which hints me to some extent. @Pelangi

1 Like

Is he right?

@Wukan his valueable time in typing the answer will be highly appreciated if he understood the question properly and addressed it properly too, which is not the case.

@SalahAdDin nope he’s still wrong.

Finally, Did you get a properly answer?

Variables setted by ur method becomes nullptr right after u return widget, so u cant work with them anywhere but inside RebuildWidget(), any ideas how to keep those references?

Just to wrap things up. This is the actual answer to the original post, BUT there still one error, for what I can understand (other than the missing validity check which Shohei noted himself).

I spent quite a while trying to understand why RootWidget->Slot is null for me while it’s not for Shohei. Well the answer is that it’s null for Shohei too, we just both wrapped the operations on it inside of an if block, which never executes. Root widget has no container, until is passed to container->AddChild(RootWidget) [which makes it no longer a root widget], and the container gives the slot to the widget.
So, in the code screenshot above everything between RootWidget = …; and WidgetTree->RootWidget = RootWidget; is not needed as it won’t ever be executed.

Please correct me if I’m wrong, bacause with UE I’m never sure I understand.

i think this video will be helpfull. How to Spawn/Create Widget in Unreal Engine C++ - YouTube

After digging into UUserWidget, found that setup the widget layout in NativeOnInitialized instead of NativeConstruct(). I Post the example code here and please noted that I put the code in an folder name UI

Public/UI/SCrosshair.h

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "SCrosshair.generated.h"

class UImage;
class UCanvasPanel;
/**
 * 
 */
UCLASS()
class ACTIONROGUELIKE_API USCrosshair : public UUserWidget
{
	GENERATED_BODY()

protected:
	virtual void NativeOnInitialized() override;
};

Private/UI/SCrosshair.cpp

#include "UI/SCrosshair.h"
#include "Blueprint/WidgetBlueprintLibrary.h"
#include "Blueprint/WidgetTree.h"
#include "Components/CanvasPanel.h"
#include "Components/CanvasPanelSlot.h"
#include "Components/Image.h"

void USCrosshair::NativeOnInitialized()
{
	Super::NativeOnInitialized();
	
	auto MyCanvas = WidgetTree->ConstructWidget<UCanvasPanel>(UCanvasPanel::StaticClass());
	if(MyCanvas)
	{
		const FString tempIconPath = "Texture2D'/Game/UI/StyleBrush/FirstPersonCrosshair.FirstPersonCrosshair'";
		UTexture2D* tempTexture  =  LoadObject<UTexture2D>(this,*tempIconPath);
		auto CrossImage = WidgetTree->ConstructWidget<UImage>();
		CrossImage->SetBrush(UWidgetBlueprintLibrary::MakeBrushFromTexture(tempTexture));
		//CrossImage->SetBrushSize(FVector2D(16.0f,16.0f));
		MyCanvas->AddChild(CrossImage);
		const auto tempSlot =  Cast<UCanvasPanelSlot>(CrossImage->Slot);
		if(tempSlot)
		{
			tempSlot->SetAutoSize(true);
			tempSlot->SetOffsets(FMargin(0,0));
			tempSlot->SetAnchors(FAnchors(0.5f,0.5f));
		}
		WidgetTree->RootWidget = MyCanvas;
	}
}
3 Likes

You should appreciate his time no matter what. He’s a stranger online spending hours trying to help an ungrateful, entitled, sensitive stranger, for free.

This does not 100% work for me. The widget gets constructed, but as soon as I extend it in BP and add children, they get bugged out.

Here is an example:

TSharedRef<SWidget> UMessageBoxWidget::RebuildWidget()
{
    auto rootWidget = Cast<UPanelWidget>(WidgetTree->RootWidget);
    if (!rootWidget)
    {
        rootWidget = WidgetTree->ConstructWidget<UCanvasPanel>(UCanvasPanel::StaticClass(), TEXT("RootWidget"));
        auto slot = Cast<UCanvasPanelSlot>(rootWidget->Slot);
        if (slot)
        {
            slot->SetAnchors(FAnchors(0, 0, 1, 1));
            slot->SetOffsets(FMargin(0, 0, 0, 0));
        }
        WidgetTree->RootWidget = rootWidget;

        
    }

    auto widget = Super::RebuildWidget();

    if (rootWidget && WidgetTree)
    {
        auto image = WidgetTree->ConstructWidget<UImage>(UImage::StaticClass(), TEXT("Background"));
        rootWidget->AddChild(image);
        auto slot = Cast<UCanvasPanelSlot>(image->Slot);
        if (slot)
        {
            slot->SetAnchors(FAnchors(0, 0, 1, 1));
            slot->SetOffsets(FMargin(0, 0, 0, 0));
        }
    }
    return widget;
}

I create CanvasPanel as root and add background image. It looks ok at first glance in UMG editor, but the moment I drag in text, this happens:

Also I can no longer delete the TextBlock or do anything with it. I have also tried it with UBorder instead of an image. Am completely stumped… any help would be appreciated.

Wow this thread is an embarrassment

5 Likes

If you want to modify the widget in BP, don’t create the RootWidget in C++ but instead setup yout RootWidget as a UPROPERTY and set it as meta=(BindWidget). Switch to BP and create a UPanel widget and name it RootWidget and set it as a variable (the names must match).

This should allow you to customize the UMG widget in BP.

1 Like

Se mi posso permettere sbagliate tutte e due in realta nessuno di vuoi potrebbe farlo funzionare cosi perche manca una cosa fondamentale integrare i moduli "Slate "e “slate core” perche UMG non funziona bene senza il modulo Slate = e loriginale anche unreal 5 e stato interamente fatto con Slate se non lo integri non funziona nulla e da tante anomalie perche UMG e solo la cover nuova allafine e Slate che comanda poi quindi lerrore sta inmezzo usare interamente Slate o usarlo integrando UMG , la seconda cosa e vedere se il codice worka mi passate il codice ? scusate la mia interruzione non volevo disturbarvie scusate il mio inglese

Hum… To sum up, it is possible or not to create widget in pure C++, in 2023 with UE 5.2 !?

1 Like

Yes it’s definitely possible, and I just did it today based on the various responses above.

The most important bits are to initialize the RootWidget as a CanvasPanel, then the next most important bit is to do it in NativeOnInitialized and not NativeConstructor.

Here’s some quick and dirty actual code that worked for me:

3 Likes

Yeah this doesn’t work for me. I’ve tried every answer suggested in this post. I’ve tried solutions in Initialize(), NativeConstruct(), NativeOnInitialized(), and RebuildWidget(). In every case the UMG’s hierarchy is blank. Unbelievable that we can’t have an easy way to add UMG via C++ in 2024.

Looks like I need to go down the rabbit hole that is UWidgetBlueprintGeneratedClass. Smh.

2 Likes

It looks like this is the correct solution.

Check out the link for the details:

For quick reference:

  • Mark your U*Widget* member variable as UPROPERTY(meta = (BindWidget))
  • You may add BlueprintReadOnly if you want access to it in BP as if you marked IsVariable
  • Create a BP deriving from your C++ class. You need to add all members defined with BindWidget by hand to hierarchy and name them exact name in C++.
  • In C++, your member variables will be available in runtime. BP will generate and set them for you.
  • Alternatively, you may use BindWidgetOptional for optional widgets. BindWidget will not let you compile BP if they dont exist.