虚幻4渲染编程(工具篇)【第四卷:CustomizeDetailPanelForPlugin】

我的博客目录:

小IVan:专题概述及目录​zhuanlan.zhihu.com图标

在这里强烈吐槽一下epic的官方文档,有些文档写了等于什么都没写!!!十分粗略!

来给篇链接感受一下

Details 面板自定义​api.unrealengine.com图标

我表示90%的人看了这文档后不知道在说什么,什么都写不出来。然而这部分知识其实对我们写各种工具十分重要。先上效果吧:

v2-e6e8c02b4a7e5f5554d054074450d593_b.jpg

如果我们想写这么一个界面的话,全部自己手写各种SNew的话至少要上千行代码,这实在太夸张了。为了节省时间我们肯定要选择最简单的方式来,那么就是使用虚幻已有的组件。但是你会发现虚幻根本不让我们直接用这些组件。

正确的做法是使用虚幻的PropertyEditor模块来把我们需要的信息映射倒面板上,而不是一个一个手动写手动SNew。下面就来拆分一下我们要做一个复杂插件面板需要做哪些事情:

【1】我们需要一个插件window,这一步在前几卷中已经详细列出了开发方法。

【2】我们需要一个类作为我们的容器,我们向这个类中填各种数据。

【3】我们需要一个派生自IDetailCustomization的类来重新定义容器类的Detail信息

【4】我们需要一个派生自IDetailRootObjectCustomization的类来root我们的容器类

【5】我们需要吧容器类和IDetailsView类绑定,然后在UI上创建IDetailsView

可能步骤有点多,还是感觉很晕,那么下面就一步一步来实现它吧


首先我们要创建插件的slate类,注意那个IDetailsView,它就是将会被创建倒工具UI上的Slate。

v2-64fbd35df2e292e883669bd1d1225a7c_b.jpg

然后我们要定义两个Customization类

v2-549603c853454bb213d7d57b250eaf6f_b.jpg

最后是我们用来映射属性的容器类

v2-f85eb3596cfb9eb1b9d1da297fbe46d5_b.jpg

然后在源文件中我们去实现插件window的slate的construct

v2-910cf17524dab277867a2b2b2ed959c5_b.jpg

这里我们先拿到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里的数据就可以了。

v2-34b28f79e6460fcb7a4a1cb91cdf73d6_b.jpg
v2-808c0b0cbcb5335664bdc8c9ed35a044_b.jpg


最后再来梳理下整个思路:

【1】我们在敲工具的时候发现,如果这个工具里有大量的数据,需要加载一个物体的属性,这时候如果还是自己去手动snew的话是个非常恐怖的工作量,为了避免,所以我们使用虚幻自带的数据映射系统把数据映射倒我们的UI上。

【2】想要映射,就需要使用IDetailsView。而IDetailsView的创建是由PropertyEdtor模块负责的,创建了IDetailsView之后我们需要把想要映射的UObject和它进行绑定。绑定好以后加到我们的UI插槽里即可。

【3】具体的绑定和创建过程见上面的代码。

【4】我们在映射完物体的数据之后我们需要操作它啊,这时候怎么办呢,这时候就用到了

IDetailCustomization。我们可以在detail面板里加按钮,加各种我们自己snew的控件。


Enjoy it !!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cpongo11

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值