Creating widget C++

I am trying to create a super basic widget in C++
I want a canvas that holds just a black image that covers all the screen.
I dont know what is missing but I create an instance and add to viewport and nothing
is there. Also I create a blueprint user widget derived from my C++ widget
and the WBP is empty too.

What I am doing wrong?

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Components/Image.h"
#include "Components/CanvasPanel.h"
#include "fadeWid.generated.h"

UCLASS()
class MYPROJECT18_API UfadeWid : public UUserWidget
{
    GENERATED_BODY()

protected:
    virtual void NativeConstruct() override;

private:
    UPROPERTY()
    UCanvasPanel* RootCanvas;

    UPROPERTY()
    UImage* BlackImage;
};
#include "fadeWid.h"
#include "Components/Image.h"
#include "Components/CanvasPanel.h"
#include "Components/CanvasPanelSlot.h"
#include "Blueprint/WidgetTree.h"  

void UfadeWid::NativeConstruct()
{
    Super::NativeConstruct();
    
    RootCanvas = WidgetTree->ConstructWidget<UCanvasPanel>(UCanvasPanel::StaticClass(), TEXT("RootCanvas"));
    WidgetTree->RootWidget = RootCanvas;
    BlackImage = WidgetTree->ConstructWidget<UImage>(UImage::StaticClass(), TEXT("BlackImage"));
    FSlateBrush Brush;
    Brush.TintColor = FSlateColor(FLinearColor::Black);
    BlackImage->SetBrush(Brush);
    UCanvasPanelSlot* CanvasSlot = RootCanvas->AddChildToCanvas(BlackImage);
    CanvasSlot->SetAnchors(FAnchors(0.0f, 0.0f, 1.0f, 1.0f));
    CanvasSlot->SetOffsets(FMargin(0.0f, 0.0f, 0.0f, 0.0f));
}

I know I can create a child BP widget and bind components to access from code but as the widget is so simple I just want to avoid the BP side for this.

Try to add these (you may have to put it in a constructor)

this->Space = EWidgetSpace::Screen;
PrimaryComponentTick.bCanEverTick = true;
bTickInEditor = false;

cant resolve those symbols :frowning:

.h:

#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "fadeWid.generated.h"

UCLASS()
class ALS_API UfadeWid : public UUserWidget
{
	GENERATED_BODY()

public:

	UfadeWid(const FObjectInitializer& ObjectInitializer);

	virtual void NativeConstruct() override;

	UFUNCTION(BlueprintImplementableEvent, BlueprintCallable)
	void FadeIn(float time);

	UFUNCTION(BlueprintImplementableEvent, BlueprintCallable)
	void FadeOut(float time);

	UPROPERTY()
	UCanvasPanel* RootCanvas;

	UPROPERTY()
	UImage* BlackImage;
	
};

.cpp:

#include "fadeWid.h"
#include "Components/Image.h"
#include "Components/CanvasPanel.h"
#include "Components/CanvasPanelSlot.h"
#include "Blueprint/WidgetTree.h"  
#include "Components/WidgetComponent.h"

UfadeWid::UfadeWid(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
    
}

void UfadeWid::NativeConstruct()
{
    Super::NativeConstruct();
    
    RootCanvas = WidgetTree->ConstructWidget<UCanvasPanel>(UCanvasPanel::StaticClass(), TEXT("RootCanvas"));
    WidgetTree->RootWidget = RootCanvas;
    BlackImage = WidgetTree->ConstructWidget<UImage>(UImage::StaticClass(), TEXT("BlackImage"));
    FSlateBrush Brush;
    Brush.TintColor = FSlateColor(FLinearColor::Black);
    BlackImage->SetBrush(Brush);
    UCanvasPanelSlot* CanvasSlot = RootCanvas->AddChildToCanvas(BlackImage);
    CanvasSlot->SetAnchors(FAnchors(0.0f, 0.0f, 1.0f, 1.0f));
    CanvasSlot->SetOffsets(FMargin(0.0f, 0.0f, 0.0f, 0.0f));
}

W0ps i misled you there, comment out the 3 lines i mentioned

//this->Space = EWidgetSpace::Screen;
//PrimaryComponentTick.bCanEverTick = true;
//bTickInEditor = false;

In NativeConstruct() add WidgetTree = NewObject<UWidgetTree>(); at the very top, this is becuase in some UE version widget tree might be null, this is not the case here because if so the engine would crash but anyway…

I think you have to wrap your (UUserWidget) with UWidgetComponent so the widget would get processing power, not really need to create new files but in the .h add

class YOUR_API USomeWidgetComponent : public UWidgetComponent
{
	GENERATED_BODY()
public:
	USomeWidgetComponent(const FObjectInitializer& ObjectInitializer);
	virtual void BeginPlay() override;
};

at the very top, now add to your .cpp file
add these lines from before

this->Space = EWidgetSpace::Screen;
PrimaryComponentTick.bCanEverTick = true;
bTickInEditor = false;

to

USomeWidgetComponent::USomeWidgetComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
    this->Space = EWidgetSpace::Screen;
    PrimaryComponentTick.bCanEverTick = true;
    bTickInEditor = false;
}
void USomeWidgetComponent::BeginPlay()
{
    this->SetWidget(CreateWidget<UfadeWid>(GetWorld()));
    this->GetUserWidgetObject()->AddToViewport();
}

Now create an actor with this component attached and run the game, is it working ?
if Yes, than your widget is OK, its just you can’t add it to viewport by itself - it should be wrapped with widget component (this is the only way i managed to create pure cpp widget).
If it’s not working i suspect that the problem is with the UCanvasPanel, try to make the root UOverlay, may that will do the trick.

2 Likes

you’re a genious

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.