見出し画像

UE5 独自UIプラグインを作成する 02 ~Windowに基本的な部品を追加する~

【今回のポジティブワード】
自ら求める
この世の中は、自ら求めない人には、何も与えてくれない。
「自ら求めようとしない人」とは、「どんなことがあっても粘り強く、途中で投げ出さずに求めつづけようとしない人」という意味である。
この世の中は悪くない。教養や才能だけが重要なのではないからだ。たとえ知識やたしかな判断力があろうと、その仕事が好きでなければ、それはどうだっていいことなのである。
~アラン 幸福論 28 意欲ある人々~

Kindle Unlimitedを契約しているので、ポジティブになれる本を読んでます。
正月休みは寝正月で過ごしていたので、なかなか行動出来ないです。マンガで身に付くシリーズをパラパラ読んでいました。
アランの幸福論を読んでいていて「新年始まってからあーしよう、こーしよう」という考えが色々ありましたが、まずは書いてみようという気持ちになりました。
「UE5でMidiファイルを扱う」という目標が達成してしまったこともあり、目標があいまいになりモチベーションが下がっていました。まだまだ覚えないといけないことが沢山あるので、粘り強く求め続けます。2022年最初から行動することの大切さを再認識できました。

昔の名著も漫画になったり、YouTubeで要約してくれたりしてくれているのでいい時代になりました。

前回は「メニューをカスタマイズする」方法について調査しました。
今回は「Windowに基本的な部品を追加する」方法について調査していきます。

前回からの続きになります。

Windowに基本的な部品を追加する

初期UIを解析する

(プラグイン名).cppのOnSpawnPluginTab関数
でWindowの部品を配置する処理を行っています。

TSharedRef<SDockTab> FpositaUIModule::OnSpawnPluginTab(const FSpawnTabArgs& SpawnTabArgs)
{
	FText WidgetText = FText::Format(
		LOCTEXT("WindowWidgetText", "Add code to {0} in {1} to override this window's contents"),
		FText::FromString(TEXT("FpositaUIModule::OnSpawnPluginTab")),
		FText::FromString(TEXT("positaUI.cpp"))
		);

	return SNew(SDockTab)
		.TabRole(ETabRole::NomadTab)
		[
			// Put your tab content here!
			SNew(SBox)
			.HAlign(HAlign_Center)
			.VAlign(VAlign_Center)
			[
				SNew(STextBlock)
				.Text(WidgetText)
			]
		];
}

SDockTab内にSBoxがあり、SBox内にSTextBlockがあるという入れ子構造になっています。

部品の入れ子構造

Boxの階層構造を作って、ButtonとTextBlockを横に並べる

Buttonとテキストを横に並べた部品を表示するように修正します。

ButtonとTextBlockを横に並べる
return SNew(SDockTab)
	.TabRole(ETabRole::NomadTab)
	[
		// Put your tab content here!
		SNew(SBox)
		[
			SNew(SVerticalBox)
			+ SVerticalBox::Slot()
			.AutoHeight()
			[
				SNew(SHorizontalBox)
				+ SHorizontalBox::Slot()
				.Padding(10.0f, 3.0f, 10.0f, 3.0f)
				.AutoWidth()
				[
					SNew(SButton)
					.Text(LOCTEXT("Button", "Button"))
				]
				+ SHorizontalBox::Slot()
				.VAlign(VAlign_Center)
				.AutoWidth()
				[
					SNew(STextBlock)
					.Text(WidgetText)
				]
			]
		]
	];

Box>VerticalBox>HorizontalBoxの階層構造を作り、HorizontalBoxにButtonとTextBlockを配置しています。

プロパティ名と設定値(数値)を横に並べる

一番よく使用するプロパティを設定するための部品セットを作成します。

SNumericEntryBoxの数値を保持するために、ヘッダーファイルに変数と関数を2つ定義します
・変数へのゲッター関数:GetPropertyNumValue
・値が変更した際の値を設定する関数:OnPropertyNumValueChanged

(プラグイン名).h

public:
	TOptional<int32> GetPropertyNumValue() const { return PropertyNumValue; }
	void OnPropertyNumValueChanged(int32 InValue);

private:
	int32 PropertyNumValue = 1;

OnPropertyNumValueChangedの処理を.cpp側に実装します。

void FpositaUIModule::OnPropertyNumValueChanged(int32 InValue)
{
	PropertyNumValue = InValue;
}

先ほどのUIにTextBlockとSNumericEntryBoxが横並びになるような処理を実装します。

// includeにヘッダーを追加する
#include "Widgets/Input/SNumericEntryBox.h"


return SNew(SDockTab)
	.TabRole(ETabRole::NomadTab)
	[
		// Put your tab content here!
		SNew(SBox)
		[
			SNew(SVerticalBox)
			+ SVerticalBox::Slot()
			.AutoHeight()
			[
				SNew(SHorizontalBox)
				+ SHorizontalBox::Slot()
				.Padding(10.0f, 3.0f, 10.0f, 3.0f)
				.AutoWidth()
				[
					SNew(SButton)
					.Text(LOCTEXT("Button", "Button"))

				]
				+ SHorizontalBox::Slot()
				.VAlign(VAlign_Center)
				.AutoWidth()
				[
					SNew(STextBlock)
					.Text(WidgetText)
				]
			]
			+ SVerticalBox::Slot()
			.AutoHeight()
			[
				SNew(SHorizontalBox)
				+ SHorizontalBox::Slot()
				.Padding(10.0f, 3.0f, 10.0f, 3.0f)
				.VAlign(VAlign_Center)
				.AutoWidth()
				[
					SNew(STextBlock)
					.Text(LOCTEXT("PropertyNum", "PropertyNum"))
				]
				+ SHorizontalBox::Slot()
				.AutoWidth()
				[
					SNew(SNumericEntryBox<int32>)
					.IsEnabled(true)
					.AllowSpin(true)
					.MinSliderValue(1)
					.MaxSliderValue(10000)
					.MinDesiredValueWidth(75)
					.Value_Raw(this, &FpositaUIModule::GetPropertyNumValue)
					.OnValueChanged_Raw(this, &FpositaUIModule::OnPropertyNumValueChanged)
				]
			]

		]
	];

詳細パネルでよく見かけるプロパティと設定値のUIを作成することが出来ました。

ButtonをクリックしたらSNumericEntryBoxの値をTextBlockに表示する

最後にButtonの入力処理を実装します。
Buttonのクリックイベントの処理を把握したいので、ButtonをクリックするとSNumericEntryBoxの値をButtonの右側のTextBlockに表示する処理を実装します。

SNumericEntryBoxの値を保持し続ける変数を追加したように、TextBlockのテキストを保持する変数を追加します。
TextBlockのテキストを保持する変数のゲッター関数(GetPropertyNumText)とクリックイベントをハンドルする関数(HandleButton)を追加します。

(プラグイン名).h

public:
	FText GetPropertyNumText() const { return PropertyNumText; }
	FReply HandleButton();

private:
	FText PropertyNumText;

クリックイベントをハンドルする関数(HandleButton)の処理を.cpp側に実装します。

FReply FpositaUIModule::HandleButton()
{
	// PropertyNumValueをFTextに変換してPropertyNumTextに設定
	PropertyNumText = FText::AsNumber(PropertyNumValue);

	return FReply::Handled();
}

最終的なOnSpawnPluginTab関数のソースコードになります。

TSharedRef<SDockTab> FpositaUIModule::OnSpawnPluginTab(const FSpawnTabArgs& SpawnTabArgs)
{
	PropertyNumText = FText::AsNumber(PropertyNumValue);

	return SNew(SDockTab)
		.TabRole(ETabRole::NomadTab)
		[
			// Put your tab content here!
			SNew(SBox)
			[
				SNew(SVerticalBox)
				+ SVerticalBox::Slot()
				.AutoHeight()
				[
					SNew(SHorizontalBox)
					+ SHorizontalBox::Slot()
					.Padding(10.0f, 3.0f, 10.0f, 3.0f)
					.AutoWidth()
					[
						SNew(SButton)
						.Text(LOCTEXT("Button", "Button"))
						.OnClicked_Raw(this, &FpositaUIModule::HandleButton)

					]
					+ SHorizontalBox::Slot()
					.VAlign(VAlign_Center)
					.AutoWidth()
					[
						SNew(STextBlock)
						.Text_Raw(this, &FpositaUIModule::GetPropertyNumText)
					]
				]
				+ SVerticalBox::Slot()
				.AutoHeight()
				[
					SNew(SHorizontalBox)
					+ SHorizontalBox::Slot()
					.Padding(10.0f, 3.0f, 10.0f, 3.0f)
					.VAlign(VAlign_Center)
					.AutoWidth()
					[
						SNew(STextBlock)
						.Text(LOCTEXT("PropertyNum", "PropertyNum"))
					]
					+ SHorizontalBox::Slot()
					.AutoWidth()
					[
						SNew(SNumericEntryBox<int32>)
						.IsEnabled(true)
						.AllowSpin(true)
						.MinSliderValue(1)
						.MaxSliderValue(10000)
						.MinDesiredValueWidth(75)
						.Value_Raw(this, &FpositaUIModule::GetPropertyNumValue)
						.OnValueChanged_Raw(this, &FpositaUIModule::OnPropertyNumValueChanged)
					]
				]

			]
		];
}

ボタンのクリック処理とTextBlockの値を動的に変更する処理です。

// ボタンのクリック処理
SNew(SButton)
.Text(LOCTEXT("Button", "Button"))
.OnClicked_Raw(this, &FpositaUIModule::HandleButton)


// TextBlockはGetPropertyNumTextでPropertyNumValueをPropertyNumTextに設定し続ける
SNew(STextBlock)
.Text_Raw(this, &FpositaUIModule::GetPropertyNumText)

Buttonをクリックすると、TextBlockがSNumericEntryBoxの値に変更されるようになりました。

Buttonをクリックすると、TextBlockがSNumericEntryBoxの値に変更される

まとめ

基本的な部品の配置と入力処理を実装することができました。少しずつ使える部品をWindowに追加していけるようにします。
ボタンと値を自由に扱うことが出来るようになったので、Viewport内を操作するのも面白そうです。
何が出来て、何が出来ないのか把握することが出来れば有益なプラグインを作成することが出来そうですね。
今年も少しずつでも前に進めるように頑張ります。

ソースコード(GitHub)

【参考URL】

【UE4】エディタ拡張(リスト編)
https://logicalbeat.jp/blog/912/


この記事が気に入ったらサポートをしてみませんか?