BLOGブログ

2014.05.27UE4UE/ Plugin

[UE4] プラグインによるエディタ拡張(3) SlateUIを使用してウィンドウを作成する

改訂バージョン: Unreal Engine 4.21

前回の記事で、メインウィンドウにメニュー項目を追加しました。

今回は、そのメニューからウィンドウを表示する手順をご紹介します。

 

1.ウィンドウを表示する

ソースコードに以下の内容を追加します。

//省略

PublicDependencyModuleNames.AddRange(
new string[]
{

//省略

“MainFrame”,
}
);

//省略

//省略
#include “Editor/MainFrame/Public/Interfaces/IMainFrameModule.h”
#include “SWindow.h”

//省略

class FMyPlugin : public IMyPlugin
{

//省略

void OnMainFrameLoad(TSharedPtr InRootWindow, bool bIsNewProjectWindow);
TWeakPtr RootWindow;
TWeakPtr MyWindow;
}

//省略

void FMyPlugin::StartupModule()
{

//省略

IMainFrameModule& MainFrameModule =
FModuleManager::LoadModuleChecked(TEXT(“MainFrame”));
MainFrameModule.OnMainFrameCreationFinished().AddRaw(
this, &FMyPlugin::OnMainFrameLoad);
}

void FMyPlugin::ShutdownModule()
{

//省略

if (FModuleManager::Get().IsModuleLoaded(“MainFrame”))
{
IMainFrameModule& MainFrameModule =
FModuleManager::LoadModuleChecked(TEXT(“MainFrame”));
MainFrameModule.OnMainFrameCreationFinished().RemoveAll(this);
}
}
void FMyPlugin::OnMainFrameLoad(TSharedPtr InRootWindow, bool bIsNewProjectWindow)
{
if ((!bIsNewProjectWindow) && (InRootWindow.IsValid()))
{
RootWindow = InRootWindow;
}
}

void FMyPlugin::OnMyToolMenu()
{
if (!MyWindow.IsValid())
{
TSharedPtr Window = SNew(SWindow)
.Title(LOCTEXT(“MyWindow”, “MyWindow”))
.ClientSize(FVector2D(300.f, 300.f));
MyWindow = TWeakPtr(Window);
if (RootWindow.IsValid())
{
FSlateApplication::Get().AddWindowAsNativeChild(
Window.ToSharedRef(), RootWindow.Pin().ToSharedRef());
}
Window->SetContent(
SNew(STextBlock)
.Text(LOCTEXT(“Hello”, “Hello”))
);
}
MyWindow.Pin()->BringToFront();
}

これで、↓のように、Helloとだけ書かれたウィンドウが表示されます。

 

ウィンドウを表示するためには、親となるUnrealEditorのメインウィンドウへの参照を保持する必要があります。

StartupModule()で”MainFrame”モジュールに対してDelegateを登録し、メインウィンドウ生成時にOnMainFrameLoad()関数が呼び出されるようにします。

OnMainFrameLoad()関数は、エディタのメインウィンドウが作成された際に、その参照をRootWindow変数に保持します。

ShutdownModule()では、その登録を破棄しています。

 

ウィンドウの生成はOnMyToolMenu()関数で行われます。

この関数は、前回の記事で作ったメニュー項目が選択された際に呼び出されます。

MyWindow変数は、自作のウィンドウへの参照です。

既にウィンドウが開いている場合には再生成せずに、既存のウィンドウを最前面に移動するだけにします。

 

Window->SetContent() でウィンドウ内にウィジェットを追加していきます。

今は単純にテキストを表示するだけの”TextBlock”を配置しています。

ウィジェットには多くの種類があり、UnrealEditorの各種UIはこれらの組み合わせで作られています。

 

2.ボタンを追加する

次に、このウィンドウにボタンを追加します。

ソースコードは以下の通りです。

 

//省略

“InputCore”,
}
);

//省略

//省略

class FMyPlugin : public IMyPlugin
{

//省略

FReply OnButtonClicked();
}

//省略

void FMyPlugin::OnMyToolMenu()
{

//省略

Window->SetContent(
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.VAlign(VAlign_Center)
.FillHeight(1.f)
.Padding(2.f)
[
SNew(STextBlock)
.Text(LOCTEXT(“Hello”, “Hello”))
]
+ SVerticalBox::Slot()
.VAlign(VAlign_Center)
.FillHeight(1.f)
.Padding(2.f)
[
SNew(SButton)
.Text(LOCTEXT(“Button”, “Button”))
.OnClicked_Raw(this, &FMyPlugin::OnButtonClicked)
]
);

//省略

}

FReply FMyPlugin::OnButtonClicked()
{
UE_LOG(LogTemp, Log, TEXT(“OnButton”));
return FReply::Handled();
}

これで↓のように、ウィンドウにボタンが追加されました。

 

ボタンには SButton ウィジェットを使用します。

また、ウィンドウ内に複数のウィジェットを配置する場合は、SVerticalBoxのような複数の子を持てるウィジェットを使用して、各ウィジェットをレイアウトします。

SVerticalBoxは、単純に全ての子を縦に並べるウィジェットです。FillHeight()に指定した値が、各項目の高さの割合になります。

 

SButton::OnClicked_Raw()で設定したOnButtnClicked()関数が、ボタンが押された際に呼び出されます。

UE_LOG()を使用して呼び出しが確認できるようにしました。

UE_LOG()の出力は、[Window -> OutputLog]から開けるログウィンドウで確認することが出来ます。

 

SlateUIの記述は、operator[]などを使用して通常のC++では見慣れない記述方法になっています。

慣れるまでは思い通りに扱うのは難しいと思いますが、エンジンのソースコードには大量のサンプルが含まれていますので、根気よく調べてみましょう。

筆者もまだまだ慣れません…

3.チェックボックスを追加する

次は、このツールにチェックボックスを追加して、ボタンが押された時にその値を取得できるようにしてみます。

ソースコードは以下のとおりです。

//省略

class FMyPlugin : public IMyPlugin
{

//省略

void OnToggleCheckBox(ECheckBoxState NewCheckedState);
ECheckBoxState GetCheckBoxState() const;
bool Check;

};

//省略

void FMyPlugin::StartupModule()
{

//省略

Check = true;
}

//省略

void FMyPlugin::OnMyToolMenu()
{

//省略

+ SVerticalBox::Slot()
.VAlign(VAlign_Center)
.FillHeight(1.f)
.Padding(2.f)
[
SNew(SCheckBox)
.OnCheckStateChanged_Raw(this, &FMyPlugin::OnToggleCheckBox)
.IsChecked_Raw(this, &FMyPlugin::GetCheckBoxState)
.Content()
[
SNew(STextBlock)
.Text(LOCTEXT(“CheckBox”, “CheckBox”))
]
]

//省略

}

FReply FMyPlugin::OnButtonClicked()
{

UE_LOG(LogTemp, Log, TEXT(“OnButton”));
if (Check)
{
UE_LOG(LogTemp, Log, TEXT(“Check=On”));
}
else {
UE_LOG(LogTemp, Log, TEXT(“Check=Off”));
}
return FReply::Handled();
}

void FMyPlugin::OnToggleCheckBox(ECheckBoxState NewCheckedState)
{
Check = (NewCheckedState == ECheckBoxState::Checked);
}
ECheckBoxState FMyPlugin::GetCheckBoxState() const
{
return Check ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
}

これで、↓のようにチェックボックスが追加されました。

 

チェックボックスには SCheckBoxウィジェットを使用します。

チェックボックスの状態が変化した時に呼び出される関数と、現在のチェックボックスの状態を取得する関数、を宣言します。

FMyPluginで状態を保持するため、bool変数を追加しています。この変数はStartupModule()内で初期化していますが、もちろんFMyPluginクラスにコンストラクタを書いてもOKです。

 

OnMyToolMenu()内でチェックボックスを追加し、上記の関数を登録しておきます。

SCheckBoxはラベルテキストを持たない代わりに、子ウィジェットを持つことが出来ます。

子ウィジェットにSTextBlockを作成することで、ラベルテキストを実現しています。

 

OnToggleCheckBox()でチェック状態のトグルを行い,GetCheckBoxState()で現在の状態を返しています。

ボタンが押された際に呼ばれるOnButtonClicked()で、保持しているチェック状態を参照して、表示内容を切り替えています。

チェックボックスの状態を切り替えてからボタンを押し、結果を確認して下さい。

 

4.目的に合ったウィジェットの探し方

今回は、いくつかの基本的なウィジェットを紹介しましたが、UnrealEngine4のSlateUIには、他にも多数のウィジェットが存在します。

公式ドキュメントのSWigetクラスのリファレンスを見ると、多数の派生クラスが記述されています。

UnrealEditorのUI自体もこのシステムで実装されていますので、エディタ本体そのものが、ツール開発のためのサンプルになります。

 

WidgetReflectorというツールを使用すると、画面に表示されているUIがどのようなウィジェットを使用して構成されているのかを確認することが出来ます。

メインメニューから [Window -> Developer Tools -> Widget Reflector] でツールを起動し「Pick Widget」ボタンを押すと、↓のように、マウスカーソルが乗っているUIの構成をリアルタイムに表示してくれます。

このツールを利用すれば、どのウィジェットを使えばそのUIが実現できるのかを簡単に調べることが出来ます。

 

今回の内容は以上になります。

次回は、自作のプラグインに画像を読み込み、メニューやツール上のアイコンとして利用する方法をご紹介して、最終回としたいと思います。

 

[UE4] プラグインによるエディタ拡張(1) 空のプラグインを追加する
[UE4] プラグインによるエディタ拡張(2) エディタのメニューに項目を追加
[UE4] プラグインによるエディタ拡張(3) SlateUIを使用してウィンドウを作成する
[UE4] プラグインによるエディタ拡張(4) 自作ツールに画像を利用する