Editor Utility Widgetで「現在選択中のアクタ」に作用するユーティリティを作りたいとき、「ところで、今、何が選択されているか」がEditor Utility Widget内で表示されていると、とても便利でわかりやすい。
ところが、調べてみたところ、たぶんBlueprintではできない匂いがする。
というわけで、C++で作ってみた。
UE4エディタの流儀に従っているかどうかは、あまり自信がありません…
おかしなところがあれば、教えてくださると助かります。
こういうことがしたい
エディタで選択したら、自動でEditor Utility Widgetにも反映したい。
いつものテーブルの上の「Statue」を選択すると、Editor Utility Widgetでも即座に「Statue」が表示される。
Escを押すなどして選択を解除したときの表示は「None」になる。
Blueprint側
Editor Utility WidgetのBlueprint Graphはこんな感じ。
Event Pre Construct
-
SinglePropertyViewCurrentSelection
は現在選択中のアクタを表示するためのもの。- このEditor Utility Widgetのメンバ変数を使用するので、
Set Object
にはSelf
を渡す。 -
Set Property Name
には、このEditor Utility Widgetに用意したメンバ変数の名前"CurrentSelection"を渡す。- CurrentSelectionはActor型の変数。
- このEditor Utility Widgetのメンバ変数を使用するので、
- 次の
SetEnableSelectionChangedEvent
にTrueを渡すことで、エディタのSelection Changed Event受け取り用の初期化をする。- 具体的には、この関数の中でSelection Changed Eventにdelegateをバインドしている。(後述のC++ソースを参照)
Event On Editor Selection Changed
- エディタのSelection Changed Eventを受け取って呼び出されるBlueprint Implementable Event
-
Get Selected Level Actors
を呼び出して、現在選択中のアクタの配列を取得。- このノードは「Editor Scripting Utilitiesプラグイン」に含まれているので、こちらを有効にしておく必要がある。
- 配列が空じゃなければ、最初の1個を
CurrentSelection
にセット(そのまま表示される) - 配列が空ならば、
CurrentSelection
をNONEにする。
-
#C++側
- UEditorUtililtyWidgetを親クラスとした、自作のEditorUtilityWidgetクラスを用意する。
- USelectionというクラスの
SelectionChangedEvent
にデリゲートをバインドしておけば、呼び出してくれる。
注意:
- EditorUtilityWidgetはEditorモジュール側に定義する必要がある。
- EditorUtilityWidgetを使うには、"Blutility"モジュールと "UMG"モジュールが必要。
.Build.cs に足しておくべし。 - EditorUtilityWidgetのBlueprintの新規作成時、UEditorUtilityWidget以外の親を指定できない。
気にせず作成して、後で Class Settings > 詳細パネル > Class Options > Parent Class を自作クラスに変更すれば良い。
SelChangedEditorUtilityWidget.h
#pragma once
#include "CoreMinimal.h"
#include "EditorUtilityWidget.h"
#include "SelChangedEditorUtilityWidget.generated.h"
// Base class for custom editor utility widget which receives OnSelectionChanged from UE4 editor.
// Note that this class is defined in editor module.
//
// You need to add modules to your .Build.cs:
// - "Blutility" module for UEditorUtilityWidget
// - "UMG" module for UUserWidget which is base class of UEditorUtilityWidget.
UCLASS()
class MYPROJECT_ED_API USelChangedEditorUtilityWidget : public UEditorUtilityWidget
{
GENERATED_BODY()
public:
// ctor
USelChangedEditorUtilityWidget(const FObjectInitializer& InObjectInitializer)
: Super(InObjectInitializer)
{}
public:
// Enables to receive Selection Changed Event from the editor.
UFUNCTION(BlueprintCallable, Category = "Selection Changed Editor Utility Widget")
void SetEnableSelectionChangedEvent(bool InEnabled);
// Blueprint implementable event which is called when selection changed event.
UFUNCTION(BlueprintImplementableEvent, CallInEditor, Category = "Selection Changed Editor Utility Widget")
void OnEditorSelectionChanged();
private:
// A delegate called when selection chaged in the editor.
void OnSelectionChanged(UObject* InSelection);
// a handle for bound delegate
FDelegateHandle SelectionChangedEventHandle;
};
SelChangedEditorUtilityWidget.cpp
#include "SelChangedEditorUtilityWidget.h"
#include "Engine/Selection.h" // USelection
void USelChangedEditorUtilityWidget::SetEnableSelectionChangedEvent(bool InEnabled)
{
// bind the delegate
if (InEnabled)
{
if (/*not*/!SelectionChangedEventHandle.IsValid()) // only if not bound
{
SelectionChangedEventHandle = USelection::SelectionChangedEvent.AddUObject(
this, &USelChangedEditorUtilityWidget::OnSelectionChanged);
}
}
// if false, unbind the delegate
else
{
if (SelectionChangedEventHandle.IsValid()) // only if bound
{
USelection::SelectionChangedEvent.Remove(SelectionChangedEventHandle);
SelectionChangedEventHandle.Reset();
}
}
}
void USelChangedEditorUtilityWidget::OnSelectionChanged(UObject* InSelection)
{
USelection* Selection = Cast<USelection>(InSelection);
if (Selection)
{
OnEditorSelectionChanged(); // call the BlueprintImplementableEvent
}
}
以上です。