C++ Widget does not show anything on screen

Hello, i am learning to programming Widgets and HUD to C++ and i did this [trying][1] for learning.

I got all setup for the widget in its c++ file:

ULectureWidget::ULectureWidget(const FObjectInitializer& ObjectInitializer): Super(ObjectInitializer){
	// Set icons textures
	static ConstructorHelpers::FObjectFinder<UTexture2D> HomeIconObj(TEXT("/Game/UI/Icons/home-outline"));
	static ConstructorHelpers::FObjectFinder<UTexture2D> MenuIconObj(TEXT("/Game/UI/Icons/th-list-outline"));
	static ConstructorHelpers::FObjectFinder<UTexture2D> ArrowLeftIconObj(TEXT("/Game/UI/Icons/arrow-left-outline"));
	static ConstructorHelpers::FObjectFinder<UTexture2D> ArrowRightIconObj(TEXT("/Game/UI/Icons/arrow-right-outline"));

	if (HomeIconObj.Object != NULL) HomeIconTexture = HomeIconObj.Object;
	if (MenuIconObj.Object != NULL) MenuIconTexture = MenuIconObj.Object;
	if (ArrowLeftIconObj.Object != NULL) ArrowLeftIconTexture = ArrowLeftIconObj.Object;
	if (ArrowRightIconObj.Object != NULL) ArrowRightIconTexture = ArrowRightIconObj.Object;
}

void ULectureWidget::NativeConstruct()
{
	Super::NativeConstruct();

	UCanvasPanel* Root = WidgetTree->ConstructWidget<UCanvasPanel>(UCanvasPanel::StaticClass(), FName("Canvas"));
	// UCanvasPanel* Root = Cast<UCanvasPanel>(GetRootWidget());

	
	WidgetTree->RootWidget = Root;
	UWidget* root = GetRootWidget();
	UE_LOG(LogTemp, Warning, TEXT("Root widget class: %s"), *root->GetClass()->GetName());

	// Create buttons and set them in a slot
	HomeButton = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), FName("Home_Button"));
	HomeButton->WidgetStyle.Normal.SetResourceObject(Cast<UObject>(HomeIconTexture));
	HomeButton->WidgetStyle.Normal.SetImageSize(FVector2D(80.f, 80.f));
	HomeButton->WidgetStyle.Normal.DrawAs = ESlateBrushDrawType::Image;
	HomeButton->WidgetStyle.Normal.TintColor = FLinearColor(1.f, 0.f, .3f, 1.f);
	HomeButton->WidgetStyle.Normal.Margin = 0.f;
	// HomeButton->SetColorAndOpacity(FLinearColor(1.f, 1.f, 1.f, 0));

	UCanvasPanelSlot* HomeButtonSlot = Cast<UCanvasPanelSlot>(Root->AddChild(HomeButton));
	HomeButtonSlot->SetAnchors(FAnchors(.0f, .0f, .0f, .0f));
	HomeButtonSlot->SetSize(FVector2D(80.f, 80.f));
	HomeButtonSlot->SetPosition(FVector2D(80.f, 80.f));
	//HomeButtonSlot->SetAlignment(FVector2D(.5f, .5f));

	MenuButton = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), FName("Menu_Button"));
	MenuButton->WidgetStyle.Normal.SetResourceObject(Cast<UObject>(MenuIconTexture));
	MenuButton->WidgetStyle.Normal.SetImageSize(FVector2D(80.f, 80.f));
	HomeButton->WidgetStyle.Normal.DrawAs= ESlateBrushDrawType::Image;
	MenuButton->WidgetStyle.Normal.Margin = 0.f;

	UCanvasPanelSlot* MenuButtonSlot = Cast<UCanvasPanelSlot>(Root->AddChild(MenuButton));
	MenuButtonSlot->SetAnchors(FAnchors(1.f, 0, 1.f, 0));
	MenuButtonSlot->SetSize(FVector2D(80.f, 80.f));
	MenuButtonSlot->SetPosition(FVector2D(-160.f, 80.f));

	ArrowLeftButton = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), FName("ArrowLeft_Button"));
	ArrowLeftButton->WidgetStyle.Normal.SetResourceObject(Cast<UObject>(ArrowLeftIconTexture));
	ArrowLeftButton->WidgetStyle.Normal.SetImageSize(FVector2D(80.f, 80.f));
	ArrowLeftButton->WidgetStyle.Normal.DrawAs = ESlateBrushDrawType::Image;
	ArrowLeftButton->WidgetStyle.Normal.Margin = 0.f;

	UCanvasPanelSlot* ArrowLeftButtonSlot = Cast<UCanvasPanelSlot>(Root->AddChild(ArrowLeftButton));
	ArrowLeftButtonSlot->SetAnchors(FAnchors(0, 1.f, 0, 1.f));
	ArrowLeftButtonSlot->SetSize(FVector2D(80.f, 80.f));
	ArrowLeftButtonSlot->SetPosition(FVector2D(80.f, -200.f));

	ArrowRightButton = WidgetTree->ConstructWidget<UButton>(UButton::StaticClass(), FName("ArrowRight_Button"));
	ArrowRightButton->WidgetStyle.Normal.SetResourceObject(Cast<UObject>(ArrowRightIconTexture));
	ArrowRightButton->WidgetStyle.Normal.SetImageSize(FVector2D(80.f, 80.f));
	ArrowRightButton->WidgetStyle.Normal.DrawAs = ESlateBrushDrawType::Image;
	ArrowRightButton->WidgetStyle.Normal.Margin = 0.f;

	UCanvasPanelSlot* ArrowRightButtonSlot = Cast<UCanvasPanelSlot>(Root->AddChild(ArrowRightButton));
	ArrowRightButtonSlot->SetAnchors(FAnchors(1.f, 1.f, 1.f, 1.f));
	ArrowRightButtonSlot->SetSize(FVector2D(80.f, 80.f));
	ArrowRightButtonSlot->SetPosition(FVector2D(-160.f, -200.f));

	Root->AddToRoot();

}

And i’m handling it in the player controller:

void ABookBasePlayerController::BeginPlay()
{
	// Call the base class  
	Super::BeginPlay();

	// 1. Get the current player controller
	APlayerController* PlayerController = UGameplayStatics::GetPlayerController(this, 0);

	// 2. Instead to get a camera in the level, we will create a new one
	// TODO: destroy it after leaving the level.
	FVector Location = FVector(-1600.f, 0, 1200.f);
	FRotator Rotation = FRotator(-35.f, 360.f, 0.f);
	ACameraActor* TPCamera = GetWorld()->SpawnActor<ACameraActor>(Location, Rotation);
	TPCamera->SetActorLabel(FString("TPCamera"));
		
	// 3. Setting a new View Port Target to our player
	PlayerController->SetViewTargetWithBlend(Cast<AActor>(TPCamera), 0.5f);

	// 4. Creating the widget and adding it to the viewport
	if (LectureWidgetClass) {
		LectureWidget = CreateWidget<ULectureWidget>(this, LectureWidgetClass);
		if (LectureWidget) LectureWidget->AddToViewport();
		else UE_LOG(LogTemp, Error, TEXT("Something is wrong with the widget!"));
	}

}

I setup the blueprints properly and i set a LectureWidget blueprint to WidgetClass in the player controller; all is well, the camera goes to TPCamera, but i don’t get anything in the screen, why?

I found many problems with the button slots, that’s why i created a Canvas as a root for the slots, but i get some errors: I designate the canvas component [as the root][2], without this the UserWidget [has no any root component][3](if you use GetRootWidget() function to get it) breaking the compilation:

I just simply try to emulate the blueprint logic in c++, but it does not work.

Why?

I would create the widget from the blueprint widget and to call them in c ++ I would use UPROPERTY (meta = (BindWidget)). Now if you want to believe them by code, there is no problem.

is your hud class you must initialize your UUserWidget in BeginPlay

sample:

.h:

	UPROPERTY(EditAnywhere)
		class UUserWidget* CurrentWidget;

	UPROPERTY(EditAnywhere)
		TSubclassOf<class UUserWidget> SubWidget;

.cpp:

if (SubWidget!= nullptr) {
	CurrentWidget = CreateWidget<UUserWidget>(GetWorld(), SubWidget);
	if (CurrentWidget) {
		CurrentWidget->AddToViewport();
	}
}
1 Like

First of all u need to create root widget with Init function. It wont work other way, if u need visual part of widget to be visible in Widget BP Editor u need to use NativePreConstruct(), then u can see the changes after every compile, NativeConstruct() arent working in the editor.

-h
virtual bool Initialize() override;

-cpp

bool UWIDGET::Initialize() {

    bool RESPONSE = Super::Initialize();

    if (!HasAnyFlags(RF_ClassDefaultObject)) {
        BODY = WidgetTree->ConstructWidget<USizeBox>();
        WidgetTree->RootWidget = BODY;
    }

    return RESPONSE;

}

and don’t try to add other widgets to rootwidget in Initialize function , it will crash the editor, setup root widget in Init and add other stuff to it in NativeConstruct() or NativePreConstruct(), also u’ll probably wont see all ur stuff in widget tree in bp editor, just result of compilation in preview window, u need to register those elements somehow to see them in BP editor widgetree, but i don’t know how.

here’s the way u add slots

SPACE = WidgetTree->ConstructWidget<UCanvasPanel>();
auto BODY_SLOT = BODY->AddChild(SPACE);

no need to Cast like u did.

Peace.