跳至主要內容

ED08.FAssetEditorToolkit|自定义资源编辑器

Mr.Si大约 7 分钟u++

省流

FAssetEditorToolkit

一个封装了“UE 编辑器中资产编辑器所需基础功能(如菜单、工具栏、面板注册、布局、命令系统)的一套可扩展基类框架”。

头像

前面铺垫了这么久的FAssetEditorToolkit到底是个啥?我该怎么用呢?

头像

当然是为了实现一些更加高级的功能,例如 蓝图图表、材质图表等,这种往往通过节点式的连线更加直观

头像
那我该怎么开始使用他呢?
头像

还记得咱们之前定义的自定义资产的AssetDefinitionDefault 吗?里面有一个OpenAssets 函数

	virtual EAssetCommandResult OpenAssets(const FAssetOpenArgs& OpenArgs) const override;
头像
这个我记得,这个和我们的资源编辑器有什么关系呢?
头像
有的!兄弟有的!你可以看看他默认的实现

EAssetCommandResult UAssetDefinitionDefault::OpenAssets(const FAssetOpenArgs& OpenArgs) const
{
	if (GetAssetOpenSupport(FAssetOpenSupportArgs(OpenArgs.OpenMethod)).IsSupported)
	{
		FSimpleAssetEditor::CreateEditor(EToolkitMode::Standalone, OpenArgs.ToolkitHost, OpenArgs.LoadObjects<UObject>());
		return EAssetCommandResult::Handled;
	}

	return EAssetCommandResult::Unhandled;
}


FAssetEditorToolkit | 派生类

头像

我看了!好像是用FSimpleAssetEditor 创建了对应的资源编辑器!这个FSimpleAssetEditor是个啥?

头像

FSimpleAssetEditor是官方帮我们封装的最简单的一个资源编辑器。下面看看有哪些官方大大给我们封装的模块:

1. FAssetEditorToolkit(基础类)

  • 是所有资源编辑器的基础类,但本身不带复杂业务逻辑
class FAssetEditorToolkit : public FBaseToolkit, public IAssetEditor

2. FWorkflowCentricApplication(工作流驱动型编辑器)

面向复杂的、多面板、多模式切换的编辑器(如蓝图编辑器)

class FWorkflowCentricApplication : public FAssetEditorToolkit
  • 内置 FApplicationMode 机制,可动态定义工作流

3. FSimpleAssetEditorToolkit(轻量级编辑器)

class FSimpleAssetEditorToolkit : public FAssetEditorToolkit
  • 无复杂的 ApplicationMode 和 Tab 分布结构
  • 用于结构简单的编辑器,如只包含一个 Details 面板或 Preview 视图
  • 通常通过创建一个简单布局,快速搭建 UI

FAssetEditorToolkit | 编辑器面板

头像
基础的编辑器面板一般包括哪些?
头像
为了方便你理解,BABA给你画个图。
区域名称构建方式
顶部菜单栏Menu BarFMenuBarBuilder
工具栏Tool BarFToolBarBuilder
主要区域中心面板FTabManager + DockTab
底部栏Status BarSStatusBar + FStatusBarItem

开干

1. build.cs引入模块

 PublicDependencyModuleNames.AddRange( new string[] {"UnrealEd",});

2. 创建 FAssetEditorToolkit

头像

FAssetEditorToolkit本身是一个抽象类,并不会包含业务逻辑,习惯上我们可以再抽象一层用来实现业务接口。


//抽象
class  ISuperComboGraphBlueprintEditor :
public FWorkflowCentricApplication{};

//具体派生实现类
class  FSuperComboGraphAssetsEditor : 
public ISuperComboGraphBlueprintEditor, public FGCObject,
public FNotifyHook, public FEditorUndoClient{ };

3. 基础接口

头像

FAssetEditorToolkit官方注释上说是抽象类,那必然有一些纯虚函数接口,哪些是必须实现的?为什么必须实现呢?

头像
如果你不实现,系统无法正确识别你的编辑器是谁、如何命名窗口。

    //唯一名称(内部识别名)。
	virtual FName GetToolkitFName() const override
	{
	    return FName("名字");
	      
	};	// Must implement in derived class!			
	
	//显示名称(用于标签栏 / 窗口标题等 UI 中)。
	virtual FText GetBaseToolkitName() const override
	{
	    return FName("标题名称");
	      
	};	// Must implement in derived class!		
	
	// World-Centric 模式(嵌入主编辑器窗口中)打开时,Tab 标签的前缀。
	virtual FString GetWorldCentricTabPrefix() const override 
	{
	    return LOCTEXT("WorldCentricTabPrefix", "Super ComboGraph ").ToString();
	};	// Must implement in derived class!
	

World-Centric 模式

头像

这里的 World-Centric 模式是什么?

头像
看下面的表格
模式外观描述
World-Centric编辑器嵌入在主编辑器窗口,作为一个 Tab 显示
Standalone编辑器作为一个新的独立窗口单独弹出

头像

接着咱们可以以 Properties Tab(属性面板)见之前的 DetailView为例

4. 定义|TabId

.h
static const FName PropertiesTabId;

5. 创建|CreateXXXWidget

头像
正式注册前,咱们应该将我们的属性页面先创建出来
.h
void CreateInternalWidgets();

6. 注册| RegisterTabSpawners

头像

然后去TabManger中注册咱的属性面板

头像
前面的直通车我懒得看,也没兴趣看,大胆的问一句属性面板是啥?
头像

属性面板是利用反射机制;将你类中的成员变量例如hello baba反射到一个SCompoundWidget中绘制显示的模块。这里需要挂载到对应的SDockTab中显示。

.h
virtual void RegisterTabSpawners(const TSharedRef<class FTabManager>& TabManager) override;
virtual void UnregisterTabSpawners(const TSharedRef<class FTabManager>& TabManager) override;

7. 构建| SpawnTab_XXX

头像
为什么要传入回调函数?
头像
它本质上是一个委托

头像

TabManger内部以FTabSpawner(Map)维护我们的SDockTab

头像

SO ! RegisterTabSpawner 中需要传入具体实现咱的SDockTab回调

.h
/** Properties tab 属性标签 */
TSharedPtr<class IDetailsView> SuperComboGraphProperties;

8.插入|Layout布局

头像
完事了插入到咱们的Tab中。
.h
/** 创建布局 */
TSharedRef<FTabManager::FLayout> CreateEditorLayout();

9. 初始化

FAssetEditorToolkit::InitAssetEditor(
	Mode,
	InitToolkitHost,
	TEXT("SuperComboGraphEditor"),
	StandaloneDefaultLayout,
	false,
	true,
	ObjectToEdit,
	false
);
头像

为什么不直接重写InitAssetEditor ?

头像
因为这玩意压根不是虚函数。只能直接调用

完整案例

.h

//抽象
ISuperComboGraphBlueprintEditor : public FWorkflowCentricApplication

class  FSuperComboGraphAssetsEditor : public ISuperComboGraphBlueprintEditor
{
public :

	FSuperComboGraphAssetsEditor(){};
	virtual ~FSuperComboGraphAssetsEditor() override;
	
	/** 初始化SuperComboGraphAssetsEditor */
	void InitAssetsEditor(const EToolkitMode::Type Mode, const TSharedPtr<class IToolkitHost>& InitToolkitHost,UObject* ObjectToEdit);
	
	/** IToolkit interface */
	virtual FName GetToolkitFName() const override;
	virtual FText GetBaseToolkitName() const override;
	virtual FString GetWorldCentricTabPrefix() const override;

	virtual void RegisterTabSpawners(const TSharedRef<class FTabManager>& TabManager) override;
	virtual void UnregisterTabSpawners(const TSharedRef<class FTabManager>& TabManager) override;
private:
	/** 创建控件 */	
	void CreateInternalWidgets();
	/** 创建标签页 */
	TSharedRef<SDockTab> SpawnTab_Properties(const FSpawnTabArgs& Args) const;
	/** 创建布局 */
	TSharedRef<FTabManager::FLayout> CreateEditorLayout();
private:
	/** Properties tab 属性标签 */
	TSharedPtr<class IDetailsView> SuperComboGraphProperties;
	/**	The tab ids for all the tabs used */
	static const FName PropertiesTabId;
};