3

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.

  • Name is my text variable, which I want to change
  • dialogBottom is the name of widget with this variable

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

JeJo
  • 30,635
  • 6
  • 49
  • 88
Amazing User
  • 3,473
  • 10
  • 36
  • 75

2 Answers2

5

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.

JeJo
  • 30,635
  • 6
  • 49
  • 88
  • I adder nullptr and initialize `Name` before if, because there is no dafault constructor for `UUserWidget` class, but it is still null. Added code – Amazing User Aug 02 '20 at 08:13
  • 1
    @DimaKozyr The function `GetWidgetFromName` returns, uobject widget corresponding to a given name. Are you sure you have a widget called "Name".? You can do `if(auto widget = dynamic_cast(GetWidgetFromName(TEXT("Name")))) { Name = widget; }` By this you will make sure, it has been succesfully cased to parent and not `nullptr`, before assigning to the `Name`. – JeJo Aug 02 '20 at 08:25
  • Thanks, for help, I edited wy question. `Name` is my text variable, which I want to change and `dialogBottom` is name of widget. And with this code `Name` is still null – Amazing User Aug 02 '20 at 08:53
  • 1
    @DimaKozyr Then you have your answer in front of you: 1. Could be that there is no widget called "Name" 2. It is not possible to cast the `UWidget*` to a `UTextBlock*`. You might need a redesign of how to do this. – JeJo Aug 02 '20 at 08:57
2

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).

Matt Coubrough
  • 3,739
  • 2
  • 26
  • 40
  • 1
    This is why I suggested in the comments to do `if(auto widget = dynamic_cast(GetWidgetFromName(TEXT("Name")))) { Name = widget; Name->SetText(FText::FromString(text)); }`, which will handles these all issues. – JeJo Aug 02 '20 at 08:37