🍪
【UE5】SlateをEditorUtilityWidgetで使う際にハマったこと
概要
この記事は一人アドベントカレンダー by ダリアの24日目の記事です。
今回はSlateだけで使える ClassFilter
という機能をEditorUtilityWidgetで呼び出すように実装した際に得た知見を備忘録も兼ねてまとめようと思います。
想定してるイメージは下記となります。
Slateの参考になれば幸いです。
環境
UE5.4.4
やったこと
まずクラスの全体図を書いて詰まったところを説明します。
ExampleClassFilter.h
#pragma once
#include "CoreMinimal.h"
#include "Components/ContentWidget.h"
#include "Filters/SFilterBar.h"
#include "ClassFilterWidget.generated.h"
struct ExampleType : TSharedFromThis<ExampleType>
{
public:
virtual ~ExampleType() {}
protected:
ExampleType() {}
};
class SClassFilterWidget : public SCompoundWidget
{
public:
SLATE_BEGIN_ARGS(SClassFilterWidget)
{
}
SLATE_END_ARGS()
void Construct(const FArguments& InArgs);
bool CompareItemWithClassName(ExampleType InItem, const TSet<FTopLevelAssetPath>& AssetClassPaths);
void OnFilterChanged();
TSharedPtr<SFilterBar<ExampleType>> FilterListPtr;
TSharedPtr<SSearchBox> SearchBoxPtr;
};
UCLASS()
class EXAMPLEEUWCLASSFILTEREDITOR_API UClassFilterWidget : public UContentWidget
{
GENERATED_BODY()
protected:
virtual TSharedRef<SWidget> RebuildWidget() override;
virtual void ReleaseSlateResources(bool bReleaseChildren) override;
protected:
TSharedPtr<SClassFilterWidget> ClassFilterWidgetPtr;
};
#include "ClassFilterWidget.h"
#include "Widgets/Input/SSearchBox.h"
void SClassFilterWidget::Construct(const FArguments& InArgs)
{
FilterListPtr = SNew(SFilterBar<ExampleType>)
.OnCompareItemWithClassNames(this,&SClassFilterWidget::CompareItemWithClassName)
.OnFilterChanged(this, &SClassFilterWidget::OnFilterChanged);;
ChildSlot
[
FilterListPtr.ToSharedRef()
];
}
TSharedRef<SWidget> UClassFilterWidget::RebuildWidget()
{
ClassFilterWidgetPtr = SNew(SClassFilterWidget);
return SNew(SVerticalBox)
+SVerticalBox::Slot()
[
ClassFilterWidgetPtr.ToSharedRef()
];
}
void UClassFilterWidget::ReleaseSlateResources(bool bReleaseChildren)
{
Super::ReleaseSlateResources(bReleaseChildren);
ClassFilterWidgetPtr.Reset();
}
void SClassFilterWidget::OnFilterChanged()
{
UE_LOG(LogTemp,Log,TEXT("ClassFilterWidget::OnFilterChanged"));
}
bool SClassFilterWidget::CompareItemWithClassName(ExampleType InItem,
const TSet<FTopLevelAssetPath>& AssetClassPaths)
{
return true;
}
SharedPtrで保持するはずがSharedRefになっていた
最初はこう書いてました。
//本当はTSharedPtrにしないといけない
TSharedRef<SClassFilterWidget> VerticalBoxPtr;
下記でビルドすると
TSharedRef<SWidget> UClassFilterWidget::RebuildWidget()
{
ClassFilterWidgetPtr = SNew(SClassFilterWidget)
return ClassFilterWidgetPtr.ToSharedRef()
}
以下のコンパイルエラーが出てました。
Trying to use new with any child from SWidget produces:
error C2248: ‘FSlateControlledConstruction::operator new’ : cannot access private member declared in class ‘FSlateControlledConstruction’
解決策はSharedRefをSharedPtrに変えることでした。
追加したSlateが表示されない
この部分が最初実装した際に何も表示されてない状態になっていました。
FilterListPtr = SNew(SFilterBar<ExampleType>)
.OnCompareItemWithClassNames(this,&SClassFilterWidget::CompareItemWithClassName)
.OnFilterChanged(this, &SClassFilterWidget::OnFilterChanged);
ウィジェットリフレクタで作成は出来たのがわかったので、試しにSlotで候補を探していた所ChildSlotというのを見つけて、それを追加したら表示されるようになりました。
FilterListPtr = SNew(SFilterBar<ExampleType>)
.OnCompareItemWithClassNames(this,&SClassFilterWidget::CompareItemWithClassName)
.OnFilterChanged(this, &SClassFilterWidget::OnFilterChanged);
//下記を呼ばないと表示されない
+ChildSlot
+[
+ FilterListPtr.ToSharedRef()
+];
記事は以上となります。
ここまで読んでいただきありがとうございます。
Discussion