Amazing User
Amazing User

Reputation: 3563

Why variable is null in Unreal Engine?

I want to call function, which changes the text inside the widget.

There is a virtual function NativeConstruct, which calls automatically. And it changes text of widget, but I need to call function F1 and send a text to it, which I want to display. But when I call it, the variable Name is nullptr. And by some reason, it is not nullptr, when program call NativeConstruct.

Edited

UAccessWidgetFromCpp* AccessWidgetFromCpp 
= CreateWidget<UAccessWidgetFromCpp>(
      GetWorld()->GetFirstPlayerController(), UAccessWidgetFromCpp::StaticClass()
   );

if (AccessWidgetFromCpp)
{
   AccessWidgetFromCpp->F1("222");
   widgetDialogBottomInstance->AddToViewport();
}

UCLASS()
class HOME_API UAccessWidgetFromCpp : public UUserWidget
{
   GENERATED_BODY()

public:
   UPROPERTY(BlueprintReadOnly, meta = (BindWidget))
   class UTextBlock* Name = nullptr;

   UFUNCTION()
   void F1(FString text);
};

void UAccessWidgetFromCpp::F1(FString text)
{
   if (auto widget = dynamic_cast<UTextBlock*>(GetWidgetFromName(TEXT("Name"))))
   {
      Name = widget;
      Name->SetText(FText::FromString(text));
   }
}

enter image description here

enter image description here

Upvotes: 3

Views: 6040

Answers (2)

JeJo
JeJo

Reputation: 32982

Your UPROPERTY the Name has not initialized to nullptr in the beginning. Therefore, it could contain any garbage value inside it.

Initialize it to nullptr in the class definition or in the constructor of UAccessWidgetFromCpp(if any). For instance, this will fix the issue

UPROPERTY(BlueprintReadOnly, meta = (BindWidget))
class UTextBlock* Name = nullptr;
//                     ^^^^^^^^^^

Regarding the new update:

First of all, you should avoid using c-style casting in C++. Secondly, the function GetWidgetFromName returns, uobject widget corresponding to a given name. Therefore you should be sure about having one with "Name".

Otherwise, make your code safe by double-checking the nullptr scenarios.

if(auto widget = dynamic_cast<UTextBlock*>(GetWidgetFromName(TEXT("Name")))) 
{
    Name = widget;
    Name->SetText(FText::FromString(text));
}

Even now you do not reach the line Name->SetText(FText::FromString(text)); means either you have no widget called "Name" or it is not possible to cast the UWidget* to a UTextBlock*. You might need a redesign of how to do this.

Upvotes: 5

Matt Coubrough
Matt Coubrough

Reputation: 3829

Remember to practise defensive programming! Initialize ptr values to nullptr - never assume variables are initialised in C++. The code if(Name) does not check if a UObject is valid, it just checks that there is some value in the variable - and that value will be some garbage value if the variable has not been initialised.

Furthermore, I'd recommend checking variables (that might possibly be null) immediately prior to dereferencing them.

according to the UE4 docs:

GetWidgetFromName returns the uobject widget corresponding to a given name

If there is no uobject widget corresponding to the given name (eg. due to a typo in the supplied text or some code logic error), the UE4 docs are not explicit and I haven't tested it personally, but I would assume that nullptr will be returned. If so, the null return would happen after your if(Name) check yielding a nullptr dereference.

ie.

void UAccessWidgetFromCpp::F1(FString text)
{
    if (Name)
    {
        Name = (UTextBlock*)GetWidgetFromName(TEXT("Name"));
        // if there is no Widget with name "Name" then the variable Name 
        // may now be null even if it wasn't at the if check earlier
        Name->SetText(FText::FromString(text));
    }
}

Hope that clarifies (naming the widget variable "Name" certainly doesn't help).

Upvotes: 2

Related Questions