LoginSignup
10
10

More than 3 years have passed since last update.

[UE4]C++でアセットパスからWidget Blueprintを動的に生成(CreateWidget)する方法について

Last updated at Posted at 2020-08-18

はじめに

お仕事で本件について調べたので、自分用メモも兼ねてご共有

といっても…ほぼ以下の記事のUserWidget版だけだったりします(素晴らしい記事をありがとうございます!)
[UE4] C++で動的にアクターを生成(スポーン)する方法で一番実用的だった方法
【UE4】同期的なアセットのロード方法とデメリット

検証環境:UE4.25.3

C++でアセットパスからUserWidgetClassを生成する方法

Widgetを作成するCreate Widgetを使うためには下図のノードにおけるClassピン、具体的には生成したいWidgetのUserWidgetClassを用意する必要があります。
image.png

いくつか方法がありますが、その中から使いやすい方法をご紹介。

LoadSynchronousを使う方法

#include "Blueprint/UserWidget.h"

FString path = "/Game/UMG_Test.UMG_Test_C";
TSubclassOf<class UUserWidget> WidgetClass = TSoftClassPtr<UUserWidget>(FSoftObjectPath(*Path)).LoadSynchronous();

LoadObjectを使う方法

 #include "Blueprint/UserWidget.h"

 FString path = "/Game/UMG_Test.UMG_Test";
 TSubclassOf<class UUserWidget> WidgetClass;
 UBlueprint* BP = LoadObject<UBlueprint>(NULL, *Path);
 if (BP != nullptr)
 {
    WidgetClass = BP->GeneratedClass;
 }

どちらも有効ですが、ソフトリファレンスであるTSoftClassPtrを使うLoadSynchronousの方が非同期ロード対応やその他の管理が楽になるのでオススメです。

C++で指定のUserWidgetをCreateWidgetする方法

CreateWidgetをC++で実行する場合は

UserWidget.h
template <typename WidgetT = UUserWidget, typename OwnerT = UObject>
WidgetT* CreateWidget(OwnerT* OwningObject, TSubclassOf<UUserWidget> UserWidgetClass = WidgetT::StaticClass(), FName WidgetName = NAME_None)
{
    static_assert(TIsDerivedFrom<WidgetT, UUserWidget>::IsDerived, "CreateWidget can only be used to create UserWidget instances. If creating a UWidget, use WidgetTree::ConstructWidget.");

    static_assert(TIsDerivedFrom<OwnerT, UWidget>::IsDerived
        || TIsDerivedFrom<OwnerT, UWidgetTree>::IsDerived
        || TIsDerivedFrom<OwnerT, APlayerController>::IsDerived
        || TIsDerivedFrom<OwnerT, UGameInstance>::IsDerived
        || TIsDerivedFrom<OwnerT, UWorld>::IsDerived, "The given OwningObject is not of a supported type for use with CreateWidget.");

    SCOPE_CYCLE_COUNTER(STAT_CreateWidget);

    if (OwningObject)
    {
        return Cast<WidgetT>(UUserWidget::CreateWidgetInstance(*OwningObject, UserWidgetClass, WidgetName));
    }
    return nullptr;
}

または、

WidgetBlueprint.h
UCLASS(meta=(ScriptName="WidgetLibrary"))
class UMG_API UWidgetBlueprintLibrary : public UBlueprintFunctionLibrary
{
    GENERATED_UCLASS_BODY()

public:
    /** Creates a widget */
    UFUNCTION(BlueprintCallable, BlueprintCosmetic, meta=( WorldContext="WorldContextObject", DisplayName="Create Widget", BlueprintInternalUseOnly="true" ), Category="Widget")
    static class UUserWidget* Create(UObject* WorldContextObject, TSubclassOf<class UUserWidget> WidgetType, APlayerController* OwningPlayer);

を呼び出すことになります。

前者は少しややこしいコードに見えますが、実際に使う上で注意すべき点はOwningObjectにはUWidget, UWidgetTree, APlayerControllr, UGameInstance, UWorldのいずれかを渡す必要があるという点です。ですので、

TSubclassOf<class UUserWidget> WidgetClass;
WidgetClass = TSoftClassPtr<UUserWidget>(FSoftObjectPath(*Path)).LoadSynchronous();
UUserWidget* UserWidget = CreateWidget<UUserWidget>(GetWorld(), WidgetClass);

といった感じで使うことができます。

サクッとした内容でしたが少しでもご参考になれば幸いです。

10
10
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
10