LoginSignup
2
0

More than 1 year has passed since last update.

【UE4】Editor Utility WidgetでSelection Changed Eventを受け取る

Last updated at Posted at 2021-08-14

Editor Utility Widgetで「現在選択中のアクタ」に作用するユーティリティを作りたいとき、「ところで、今、何が選択されているか」がEditor Utility Widget内で表示されていると、とても便利でわかりやすい。
ところが、調べてみたところ、たぶんBlueprintではできない匂いがする。
というわけで、C++で作ってみた。

UE4エディタの流儀に従っているかどうかは、あまり自信がありません… おかしなところがあれば、教えてくださると助かります。

こういうことがしたい

エディタで選択したら、自動でEditor Utility Widgetにも反映したい。

image.png

いつものテーブルの上の「Statue」を選択すると、Editor Utility Widgetでも即座に「Statue」が表示される。
Escを押すなどして選択を解除したときの表示は「None」になる。

Blueprint側

Editor Utility WidgetのBlueprint Graphはこんな感じ。

image.png

Event Pre Construct

  • SinglePropertyViewCurrentSelectionは現在選択中のアクタを表示するためのもの。
    • このEditor Utility Widgetのメンバ変数を使用するので、Set ObjectにはSelfを渡す。
    • Set Property Nameには、このEditor Utility Widgetに用意したメンバ変数の名前"CurrentSelection"を渡す。
      • CurrentSelectionはActor型の変数。
  • 次の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 を自作クラスに変更すれば良い。

image.png

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
    }
}

以上です。

2
0
0

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
2
0