【问题标题】:Why variable is null in Unreal Engine?为什么虚幻引擎中的变量为空?
【发布时间】:2020-11-22 14:03:39
【问题描述】:

我想调用函数,它会改变小部件内的文本。

有一个virtual 函数NativeConstruct,它会自动调用。它会更改小部件的文本,但我需要调用函数 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));
   }
}

【问题讨论】:

    标签: c++ c++11 pointers casting unreal-engine4


    【解决方案1】:

    您的UPROPERTYName 一开始还没有初始化为nullptr。因此,它可能包含any garbage value inside it

    在类定义或UAccessWidgetFromCpp(如果有)的构造函数中将其初始化为nullptr。例如,这将解决问题

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

    关于新的更新:

    首先,你应该avoid using c-style casting in C++。其次,函数GetWidgetFromName返回,uobject widget对应一个给定的名字。因此,您应该确保使用“Name”。

    否则,请仔细检查nullptr 场景以确保您的代码安全。

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

    即使现在您还没有到达Name-&gt;SetText(FText::FromString(text)); 行,意味着您没有名为“Name”的小部件,或者无法将UWidget* 转换为UTextBlock*。您可能需要重新设计如何执行此操作。

    【讨论】:

    • 我在if之前加了nullptr并初始化了Name,因为UUserWidget类没有默认构造函数,但它仍然为null。添加代码
    • @DimaKozyr 函数GetWidgetFromName 返回对应于给定名称的uobject 小部件。您确定您有一个名为“名称”的小部件吗?你可以做if(auto widget = dynamic_cast&lt;UTextBlock*&gt;(GetWidgetFromName(TEXT("Name")))) { Name = widget; } 这样你就可以确保在分配给Name之前,它已经成功地转换为父级而不是nullptr
    • 感谢您的帮助,我编辑了 wy 问题。 Name 是我想要更改的文本变量,dialogBottom 是小部件的名称。并且使用此代码Name 仍然为空
    • @DimaKozyr 然后你的答案就摆在你面前: 1. 可能没有名为“名称”的小部件 2. 无法将 UWidget* 转换为 UTextBlock* .您可能需要重新设计如何执行此操作。
    【解决方案2】:

    记得练习防御性编程!将 ptr 值初始化为 nullptr - 永远不要假设变量是在 C++ 中初始化的。代码if(Name) not 检查 UObject 是否有效,它只是检查变量中是否存在 some value - 如果变量尚未初始化。

    此外,我建议在取消引用变量之前立即检查变量(可能为空)。

    according to the UE4 docs:

    GetWidgetFromName 返回与给定名称对应的 uobject 小部件

    如果没有与给定名称对应的 uobject 小部件(例如,由于提供的文本中的拼写错误或某些代码逻辑错误),则 UE4 文档不明确,我没有亲自测试过,但我会假设将返回nullptr。如果是这样,null 返回将发生在之后您的if(Name) 检查产生一个 nullptr 取消引用。

    即。

    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));
        }
    }
    

    希望澄清(将小部件变量命名为“名称”当然没有帮助)。

    【讨论】:

    • 这就是为什么我在 cmets 中建议做if(auto widget = dynamic_cast&lt;UTextBlock*&gt;(GetWidgetFromName(TEXT("Name")))) { Name = widget; Name-&gt;SetText(FText::FromString(text)); },它将处理所有这些问题。
    猜你喜欢
    • 2023-02-16
    • 1970-01-01
    • 1970-01-01
    • 2014-09-26
    • 2015-06-17
    • 2018-09-01
    • 2020-03-13
    • 2015-01-13
    • 2022-01-19
    相关资源
    最近更新 更多