Подключение C++ к UMG блюпринтам с помощью BindWidget
Бен UI пишет о том, как управлять логикой из C++ и настраивать UI в блюпринтах.
Один из самых распространенных вопросов, который возникает у тех, кто начинает создавать пользовательские интерфейсы на базе C++, следующий:
Как я могу управлять виджетами, созданными в блюпринтах, из C++?
Ответ звучит так: мета-свойство BindWidget.
UPROPERTY(BlueprintReadWrite, meta = (BindWidget)) class UTextBlock* TitleLabel; UPROPERTY(BlueprintReadWrite, meta = (BindWidget)) class UImage* IconImage;
Хотя об этом не говорится в документации по UPROPERTY (), это один из самых полезных тегов для вас, как для разработчика пользовательского интерфейса.
Пометив указатель на виджет как BindWidget, вы можете создать виджет с таким же именем в отнаследованном блюпринте вашего класса C++, а во время выполнения обращаться к нему из C++.
Вот пошаговый процесс создания работающего теста:
- Создайте подкласс UUserWidget в C++.
- Добавьте в него переменную-член класса, которая является UWidget* или его подклассом (например, UImage, UTextBlock и т. д.).
- Пометьте ее UPROPERTY (meta=(BindWidget)).
- Запустите редактор и отнаследуйте блюпринт от вашего класса C++.
- Создайте виджет с тем же типом и точным именем, что и ваша переменная-член класса.
- Теперь вы можете получить доступ к виджету из C++.
Код примера
#pragma once #include "CoreMinimal.h" #include "Blueprint/UserWidget.h" #include "BindExample.generated.h" UCLASS(Abstract) class UBindExample : public UUserWidget { GENERATED_BODY() protected: virtual void NativeConstruct() override; UPROPERTY(BlueprintReadOnly, meta=(BindWidget)) class UTextBlock* ItemTitle; }
#include "BindExample.h" #include "Components/TextBlock.h" void UBindExample::NativeConstruct() { Super::NativeConstruct(); // ItemTitle can be nullptr if we haven't created it in the // Blueprint subclass if (ItemTitle) { ItemTitle->SetText(FText::FromString(TEXT("Hello world!"))); } }
Теперь скомпилируйте C++ и откройте блюпринт, в который вы добавили свойство ItemTitle. При компиляции блюпринта будет выдана ошибка, если внутри вашего UserWidget нет виджета TextBlock с именем ItemTitle.
Если мы теперь добавим виджет Text и изменим его имя на соответствующее нашему C++ файлу, то ошибка компиляции исчезнет, и когда мы запустим игру, текст будет изменен на «Hello world!».
Плюсы и минусы использования BindWidget и C++
Почему мы хотим использовать BindWidget и C++ вместо того, чтобы просто написать всю нашу логику в блюпринтах?
- Легче поддерживать сложную логику на C++. Никакой борьбы со спагетти в блюпринтах.
- Проще для совместной работы, не нужно беспокоиться о блокировке блюпринтов в системе контроля версий.
- Требуется повторная компиляция, чтобы увидеть изменения. Этих временных затрат можно в некоторой степени избежать, используя **Live Coding**.
- Не-программистам сложнее увидеть, как заполняются данные, поскольку логика переносится из блюпринтов в C++.
Дополнительные виджеты
Бывают ситуации, когда у вас есть базовый класс C++ и множество различных отнаследованных блюпринтов. Например, базовый класс кнопки может иметь общую логику на C++, но вы можете создать множество различных отнаследованных блюпринтов, по одному для каждого визуального стиля. В некоторых визуальных стилях могут быть иконки, в других — текст, поэтому имеет смысл сделать виджеты текста и изображения иконок необязательными.
Чтобы сделать виджет необязательным, используйте инструкцию meta=(BindWidgetOptional). При этом не будет показана ошибка, если в блюпринте нет виджета с таким именем.
UPROPERTY(BlueprintReadWrite, meta=(BindWidgetOptional)) UTextBlock* ButtonLabel; UPROPERTY(BlueprintReadWrite, meta=(BindWidgetOptional)) UImage* IconImage;
Причуды BindWidget
- Компиляция блюпринта без виджета, отмеченного как BindWidget, приведет к ошибке. Однако запустить игру все равно можно. Если вы хотите избежать сбоев в этой ситуации, вам нужно проверить, что переменная не является nullptr.
- Обычно при установке флага «Is Variable» на виджете UserWidget он (BindWidget? — непонятно) становится доступным в редактора кода (вкладка Graph). Однако если существует свойство с таким именем, помеченное как BindWidget, единственный способ сделать его доступным в блюпринте — это добавить инструкцию BlueprintReadOnly или BlueprintReadWrite к его тегу UPROPERTY ().
- По умолчанию переменные, определенные в родительском классе C++, отображаются в списке переменных, только если установлен флажок «Show Inherited Variables» (см. скриншот).
- Виджеты с пометкой BindWidget, обнуляются в конструкторе C++, они инициализируются позже в жизненном цикле объекта. Если вам нужно сделать что-то при создании объекта, используйте функцию NativeConstruct ().
Оригинал: https://benui.ca/unreal/ui-bindwidget/