Почему в Unreal Engine переменная имеет значение null? - PullRequest
3 голосов
/ 02 августа 2020

Я хочу вызвать функцию, которая изменяет текст внутри виджета.

Есть функция virtual NativeConstruct, которая вызывается автоматически. И он изменяет текст виджета, но мне нужно вызвать функцию F1 и отправить ей текст , который я хочу отобразить. Но когда я его вызываю, переменная Name равна nullptr. И почему-то это не nullptr, при вызове программы NativeConstruct.

  • 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

введите описание изображения здесь

Ответы [ 2 ]

5 голосов
/ 02 августа 2020

Ваш UPROPERTY Name изначально не инициализирован как nullptr. Следовательно, он может содержать любое значение мусора внутри него .

Инициализировать его значением nullptr в определении класса или в конструкторе UAccessWidgetFromCpp (если есть). Например, это решит проблему

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

По поводу нового обновления:

Прежде всего, вам следует избегать использования приведения в стиле c в C ++ . Во-вторых, функция GetWidgetFromName возвращает, виджет uobject соответствующий заданному имени. Поэтому вы должны быть уверены, что у вас будет один с «Name».

В противном случае сделайте свой код безопасным, дважды проверив nullptr сценарий ios.

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

Даже теперь вы не дойдете до строки Name->SetText(FText::FromString(text));, это означает, что либо у вас нет виджета с именем «Name», либо невозможно преобразовать UWidget* в UTextBlock*. Вам может потребоваться переработка того, как это сделать.

2 голосов
/ 02 августа 2020

Не забывайте практиковать защитное программирование! Инициализируйте значения ptr равными nullptr - никогда не предполагайте, что переменные инициализируются в C ++. Код if(Name) не не проверяет, действителен ли UObject, он просто проверяет, есть ли какое-то значение в переменной - и это значение будет неким мусорным значением, если переменная имеет не инициализирован.

Кроме того, я бы рекомендовал проверять переменные (которые могут быть нулевыми) непосредственно перед их разыменованием.

в соответствии с документами UE4 :

GetWidgetFromName возвращает виджет uobject, соответствующий данному имени

Если нет виджета uobject, соответствующего данному имени (например, из-за опечатки в предоставленном text или некоторый код logi c error), документы UE4 не являются явными, и я не тестировал их лично, но я предполагаю, что nullptr будет возвращено. Если это так, возврат null произойдет после вашей if(Name) проверки с разыменованием nullptr.

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

Надеюсь, что это проясняет (называя переменная виджета "Name" уж точно не помогает).

...