为什么在虚幻引擎(Unreal Engine)中变量为null?

3

我想调用一个函数,来改变小部件内的文本。

有一个名为NativeConstructvirtual函数会自动被调用。它可以改变小部件的文本,但我需要调用函数F1并向其中传递一个text,以便显示出来。但是当我调用它时,变量Namenullptr。而在程序调用NativeConstruct时,某种原因使其不为nullptr

  • Name是我想要更改的文本变量
  • dialogBottom是带有此变量的小部件的名称

已编辑

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

2个回答

5
你的UPROPERTY中的Name在一开始没有初始化为nullptr。因此,它可能包含任何垃圾值
在类定义或UAccessWidgetFromCpp的构造函数(如果有)中将其初始化为nullptr。例如,这将解决问题。
UPROPERTY(BlueprintReadOnly, meta = (BindWidget))
class UTextBlock* Name = nullptr;
//                     ^^^^^^^^^^

关于新的更新:
首先,你应该避免在C++中使用c-style转换。其次,函数GetWidgetFromName返回与给定名称相对应的。因此,你应该确保有一个名为“Name”的小部件。
否则,通过双重检查nullptr场景来使你的代码更加安全。
if(auto widget = dynamic_cast<UTextBlock*>(GetWidgetFromName(TEXT("Name")))) 
{
    Name = widget;
    Name->SetText(FText::FromString(text));
}

即使现在你还没有到达这一行 Name->SetText(FText::FromString(text));,这意味着你要么没有名为 "Name" 的小部件,要么无法将 UWidget* 强制转换为 UTextBlock*。你可能需要重新设计如何做到这一点。

我在if之前添加了nullptr并初始化了Name,因为UUserWidget类没有默认构造函数,但它仍然为空。已添加代码。 - Amazing User
1
@DimaKozyr 函数 GetWidgetFromName 返回与给定名称对应的 UObject Widget。你确定你有一个名为 "Name" 的 Widget 吗?你可以这样做:if(auto widget = dynamic_cast<UTextBlock*>(GetWidgetFromName(TEXT("Name")))) { Name = widget; } 这样,你将确保它已经成功转换为父类并且不是 nullptr,然后再分配给 Name - JeJo
谢谢您的帮助,我已经编辑了我的问题。Name是我的文本变量,我想要更改它,而dialogBottom是小部件的名称。但是使用这段代码后,Name仍然为空。 - Amazing User
1
@DimaKozyr 那么你的答案就在你面前:1. 可能没有名为“Name”的小部件。2. 不可能将 UWidget* 强制转换为 UTextBlock*。你可能需要重新设计如何实现这一点。 - JeJo

2
请记得实践防御性编程!在C++中,将指针值初始化为nullptr-永远不要假设变量已经初始化。代码if(Name)并不检查UObject是否有效,它只是检查变量中是否有某些值-如果变量没有被初始化,则该值将是一些垃圾值。
此外,我建议在解引用可能为空的变量之前立即检查它们。
根据UE4文档:GetWidgetFromName返回与给定名称对应的uobject小部件
如果没有与给定名称对应的uobject小部件(例如由于提供的文本中有拼写错误或某些代码逻辑错误),则UE4文档不明确,我个人尚未测试,但我会认为将返回nullptr。如果是这样,空返回将发生在您的if(Name)检查之后,导致空指针解引用。
即:
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));
    }
}

希望这能澄清(将小部件变量命名为“名称”确实没有帮助)。

1
这就是为什么我在评论中建议使用 if(auto widget = dynamic_cast<UTextBlock*>(GetWidgetFromName(TEXT("Name")))) { Name = widget; Name->SetText(FText::FromString(text)); },它将处理所有这些问题。 - JeJo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接