我的博客目录:
小IVan:专题概述及目录在这里强烈吐槽一下epic的官方文档,有些文档写了等于什么都没写!!!十分粗略!
来给篇链接感受一下
Details 面板自定义我表示90%的人看了这文档后不知道在说什么,什么都写不出来。然而这部分知识其实对我们写各种工具十分重要。先上效果吧:
如果我们想写这么一个界面的话,全部自己手写各种SNew的话至少要上千行代码,这实在太夸张了。为了节省时间我们肯定要选择最简单的方式来,那么就是使用虚幻已有的组件。但是你会发现虚幻根本不让我们直接用这些组件。
正确的做法是使用虚幻的PropertyEditor模块来把我们需要的信息映射倒面板上,而不是一个一个手动写手动SNew。下面就来拆分一下我们要做一个复杂插件面板需要做哪些事情:
【1】我们需要一个插件window,这一步在前几卷中已经详细列出了开发方法。
【2】我们需要一个类作为我们的容器,我们向这个类中填各种数据。
【3】我们需要一个派生自IDetailCustomization的类来重新定义容器类的Detail信息
【4】我们需要一个派生自IDetailRootObjectCustomization的类来root我们的容器类
【5】我们需要吧容器类和IDetailsView类绑定,然后在UI上创建IDetailsView
可能步骤有点多,还是感觉很晕,那么下面就一步一步来实现它吧
首先我们要创建插件的slate类,注意那个IDetailsView,它就是将会被创建倒工具UI上的Slate。
然后我们要定义两个Customization类
最后是我们用来映射属性的容器类
然后在源文件中我们去实现插件window的slate的construct
这里我们先拿到PropertyEditor模块然后通过它创建DetailView,然后这个detailview需要和我们的容器类再绑定。最后在UI上画出容器类
下面是完整代码
头文件:
#pragma once
#include "Editor/PropertyEditor/Public/IDetailCustomization.h"
#include "IDetailRootObjectCustomization.h"
#include "IDetailsView.h"
#include "FoligeFarmer.generated.h"
DECLARE_DELEGATE(FSFoligeFarmerBackToMainUI);
class FMyCustomization;
class AMyClass;
class SFoligeFarmer : public SCompoundWidget
{
public:
SLATE_BEGIN_ARGS(SFoligeFarmer) {}
SLATE_EVENT(FSFoligeFarmerBackToMainUI, EventDelegate_BackToMainUI)
SLATE_END_ARGS()
void Construct(const FArguments& InArgs);
TSharedPtr<IDetailsView> ConfigPanel;
};
class FMyCustomization : public IDetailCustomization
{
public:
// IDetailCustomization interface
virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override;
static TSharedRef< IDetailCustomization > MakeInstance();
};
class FRootObjectCustomization : public IDetailRootObjectCustomization
{
public:
/** IDetailRootObjectCustomization interface */
virtual TSharedPtr<SWidget> CustomizeObjectHeader(const UObject* InRootObject) override
{
return SNullWidget::NullWidget;
}
virtual bool IsObjectVisible(const UObject* InRootObject) const override { return true; }
virtual bool ShouldDisplayHeader(const UObject* InRootObject) const override { return false; }
};
UCLASS()
class UMyClass : public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, category = "Test")
float TestFloat;
UPROPERTY(EditAnywhere, category = "Test")
UTexture2D* TestTexture;
UPROPERTY(EditAnywhere, Category = "Test02")
UMaterial* TestMaterial;
};
源文件
#include "FoligeFarmer.h"
#include "PropertyEditing.h"
void SFoligeFarmer::Construct(const FArguments& InArgs)
{
auto& PropertyModule = FModuleManager::LoadModuleChecked< FPropertyEditorModule >("PropertyEditor");
FDetailsViewArgs DetailsViewArgs(false, false, true, FDetailsViewArgs::HideNameArea, true);
ConfigPanel = PropertyModule.CreateDetailView(DetailsViewArgs);
ConfigPanel->SetRootObjectCustomizationInstance(MakeShareable(new FRootObjectCustomization));
ConfigPanel->SetObject(UMyClass::StaticClass()->GetDefaultObject(true), true);
ChildSlot
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.AutoHeight()
[
SNew(SBox)
.WidthOverride(300)
.MinDesiredWidth(300)
.MaxDesiredWidth(300)
[
SNew(SBorder)
[
ConfigPanel.ToSharedRef()
]
]
]
];
}
#define LOCTEXT_NAMESPACE "MyEditorModule"
TSharedRef< IDetailCustomization > FMyCustomization::MakeInstance()
{
return MakeShareable(new FMyCustomization);
}
void FMyCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
{
// This is where the core of the customization code will go.
IDetailCategoryBuilder& Cat = DetailBuilder.EditCategory(TEXT("TestFloat"));
TArray< TWeakObjectPtr< UObject > > Objects;
DetailBuilder.GetObjectsBeingCustomized(Objects);
//TWeakObjectPtr< AMyClass > MyObject = Cast< AMyClass >(Objects[0].Get());
Cat.AddCustomRow(LOCTEXT("MyWarningRowFilterString", "Search Filter Keywords"))
.WholeRowContent()
[
SNew(STextBlock)
.Text(LOCTEXT("MyWarningTest", "BaseString should not be empty!"))
];
//DetailBuilder.ForceRefreshDetails();
}
#undef LOCTEXT_NAMESPACE
现在问题来了,怎么把UI里的数据拿出来呢。答案就在我们绑定的CDO里,我们直接拿CDO里的数据就可以了。
最后再来梳理下整个思路:
【1】我们在敲工具的时候发现,如果这个工具里有大量的数据,需要加载一个物体的属性,这时候如果还是自己去手动snew的话是个非常恐怖的工作量,为了避免,所以我们使用虚幻自带的数据映射系统把数据映射倒我们的UI上。
【2】想要映射,就需要使用IDetailsView。而IDetailsView的创建是由PropertyEdtor模块负责的,创建了IDetailsView之后我们需要把想要映射的UObject和它进行绑定。绑定好以后加到我们的UI插槽里即可。
【3】具体的绑定和创建过程见上面的代码。
【4】我们在映射完物体的数据之后我们需要操作它啊,这时候怎么办呢,这时候就用到了
IDetailCustomization。我们可以在detail面板里加按钮,加各种我们自己snew的控件。
Enjoy it !!!