UE4自定义资源和编辑器(二):创建自定义编辑器

介绍

我们添加了一个UStateMachine的自定义资源,现在我们在创建一个FStateMachineEditor的编辑器类来编辑这个资源。UE4中任何的编辑器都是由一个个Tab(页签)组成,由编辑器中的TabManager管理。StateMachineEditor打开后会和蓝图编辑器类似,有默认的菜单栏和工具栏。有图表和细节面板,这里菜单栏、工具栏、图表、细节面板都是页签。
我们先创建只有默认菜单栏、工具栏、和细节面板的编辑器,后面再详细介绍图表页签的创建。

创建编辑器类

首先创建一个FStateMachineEditor编辑器类,用于编辑StateMachine资源类。FStateMachineEditor从FWorkflowCentricApplication继承则可以切换编辑模式,结构会更加清晰,建议都从FWorkflowCentricApplication继承。编辑器类额外添加了一个DocumentManager变量,DocumentManager可以替换TabManager可以用于管理所有的图表页签。

  • //StatMachineEditor.h:
class STATEMACHINEEDITOR_API FStateMachineEditor : public FWorkflowCentricApplication, public FNotifyHook, public FEditorUndoClient
{
public:
	FStateMachineEditor();
	virtual ~FStateMachineEditor();	
	//初始化编辑器函数
	void InitStateMachineEditor(const EToolkitMode::Type Mode, const TSharedPtr< class IToolkitHost >& InitToolkitHost, UStateMachine* InStateMachine);

public:
	//~ Begin FWorkflowCentricApplication Interface
	virtual void RegisterTabSpawners(const TSharedRef<class FTabManager>& InTabManager) override;
	//~ End FWorkflowCentricApplication Interface

	//~ Begin IToolkit Interface
	virtual FName GetToolkitFName() const override;
	virtual FText GetBaseToolkitName() const override;
	virtual FString GetWorldCentricTabPrefix() const override;
	virtual FLinearColor GetWorldCentricTabColorScale() const override;
	//~ End IToolkit Interface

	virtual void RegisterToolbarTab(const TSharedRef<class FTabManager>& InTabManager);
	virtual void InvokeStateMachineGraphTab(); //打开图表Tab,预留
	UStateMachine* GetStateMachine() { return StateMachine.Get(); }
	TSharedPtr<FDocumentTracker> GetDocumentManager() { return DocumentManager; }

private:
	TWeakObjectPtr<UStateMachine> StateMachine;
	TSharedPtr<FDocumentTracker> DocumentManager;
};
  • StatMachineEditor.cpp:
void FStateMachineEditor::InitStateMachineEditor(const EToolkitMode::Type Mode, const TSharedPtr<class IToolkitHost>& InitToolkitHost, UStateMachine* InStateMachine)
{
	StateMachine = InStateMachine;
	// Initialize the asset editor and spawn nothing (dummy layout)
	const TSharedRef<FTabManager::FLayout> DummyLayout = FTabManager::NewLayout("NullLayout")->AddArea(FTabManager::NewPrimaryArea());
	InitAssetEditor(Mode, InitToolkitHost, FName("StateMachineEditorApp"), DummyLayout, true, true, InStateMachine);
	//Init DocumentManager
	DocumentManager = MakeShareable(new FDocumentTracker);
	DocumentManager->Initialize(SharedThis(this));
	DocumentManager->SetTabManager(TabManager.ToSharedRef());
	// Init Mode
	AddApplicationMode(FStateMachineEditorApplicationModes::StandardMode, MakeShareable(new FStandardStateMachineEditorApplicationMode(SharedThis(this))));
	SetCurrentMode(FStateMachineEditorApplicationModes::StandardMode);
}

void FStateMachineEditor::RegisterTabSpawners(const TSharedRef<class FTabManager>& InTabManager)
{
	FWorkflowCentricApplication::RegisterTabSpawners(InTabManager);
}

FName FStateMachineEditor::GetToolkitFName() const
{
    return FName("StateMachineEditor");
}

FText FStateMachineEditor::GetBaseToolkitName() const
{
    return LOCTEXT("StateMachineEditor", "StateMachine Editor");
}

FString FStateMachineEditor::GetWorldCentricTabPrefix() const
{
    return FString();
}

FLinearColor FStateMachineEditor::GetWorldCentricTabColorScale() const
{
    return FLinearColor();
}

void FStateMachineEditor::RegisterToolbarTab(const TSharedRef<class FTabManager>& InTabManager)
{
	FAssetEditorToolkit::RegisterTabSpawners(InTabManager);
}

void FStateMachineEditor::InvokeStateMachineGraphTab()
{
	//预留
}

创建好Editor类后,需要在相关的AssetTypeAction中创建Editor类对象,在打开StateMachine资源类时创建和初始化相应的Editor类。
// AssetTypeAction_StateMachine.cpp:

void FAssetTypeActions_StateMachine::OpenAssetEditor(const TArray<UObject*>& InObjects, TSharedPtr<IToolkitHost> EditWithinLevelEditor)
{
	EToolkitMode::Type Mode = EditWithinLevelEditor.IsValid() ? EToolkitMode::WorldCentric : EToolkitMode::Standalone;
	for (UObject* Object : InObjects)
	{
		if (UStateMachine* StateMachine = Cast<UStateMachine>(Object))
		{
			TSharedRef<FStateMachineEditor> NewEditor(new FStateMachineEditor());
			NewEditor->InitStateMachineEditor(Mode, EditWithinLevelEditor, StateMachine);
		}
	}
}

创建编辑模式

FWorkflowCentricApplication继承的类可以使用和切换编辑模式。编辑模式主要是负责创建布局,并注册相应的页签类。菜单栏和工具栏可以使用默认,在编辑器初始化时设置。
为状态机创建一个“StandardMode”的编辑模式。

// StateMachineEditorApplicationModes.h

class STATEMACHINEEDITOR_API FStandardStateMachineEditorApplicationMode : public FApplicationMode
{
public:
	FStandardStateMachineEditorApplicationMode(TSharedPtr<class FStateMachineEditor> InStateMachineEditor);

	virtual void RegisterTabFactories(TSharedPtr<FTabManager> InTabManager) override;
	virtual void AddTabFactory(FCreateWorkflowTabFactory FactoryCreator) override;
	virtual void RemoveTabFactory(FName TabFactoryID) override;
	virtual void PreDeactivateMode() override {};
	virtual void PostActivateMode() override;

protected:
	TWeakPtr<FStateMachineEditor> StateMachineEditor;
	FWorkflowAllowedTabSet StardardTabFactories;
};

// StateMachineEditorApplicationModes.cpp

FStandardStateMachineEditorApplicationMode::FStandardStateMachineEditorApplicationMode(TSharedPtr<class FStateMachineEditor> InStateMachineEditor)
    : FApplicationMode(FName("StandardMode"), FStateMachineEditorApplicationModes::GetLocalizedMode)
{
	StateMachineEditor = InStateMachineEditor;

	//Save TabFactories
	//StardardTabFactories.RegisterFactory(MakeShareable(new FStateMachineGraphTabFactory(InStateMachineEditor)));
	StardardTabFactories.RegisterFactory(MakeShareable(new FStateMachineDetailsTabFactory(InStateMachineEditor)));
	//创建一个默认的布局,
	TabLayout = FTabManager::NewLayout("StardardStateMachineEditorLayout")
		->AddArea
		(
			FTabManager::NewPrimaryArea()->SetOrientation(Orient_Vertical)
			->Split
			(
				FTabManager::NewStack()
				->SetSizeCoefficient(0.186721f)
				->SetHideTabWell(true)
				->AddTab(InStateMachineEditor->GetToolbarTabId(), ETabState::OpenedTab)
			)
			->Split
			(
				FTabManager::NewSplitter()->SetOrientation(Orient_Horizontal)
				->Split
				(
					FTabManager::NewSplitter()->SetOrientation(Orient_Vertical)
					->Split
					(
						FTabManager::NewStack()
						->SetSizeCoefficient(0.80f)
						->AddTab("Document", ETabState::ClosedTab)//提供给DocumentManager使用,图表的位置
					)
				)
				->Split
				(
					FTabManager::NewSplitter()->SetOrientation(Orient_Vertical)
					->Split
					(
						FTabManager::NewStack()->SetSizeCoefficient(0.2f)
						->AddTab("Detailes", ETabState::OpenedTab)
					)
				)
			)
		);

}

void FStandardStateMachineEditorApplicationMode::RegisterTabFactories(TSharedPtr<FTabManager> InTabManager)
{
	TSharedPtr<FStateMachineEditor> Editor = StateMachineEditor.Pin();

	// Tool bar tab
	Editor->RegisterToolbarTab(InTabManager.ToSharedRef());

	// Other tabs
	Editor->PushTabFactories(StardardTabFactories);

	// Graph tab
	//Editor->GetDocumentManager()->RegisterDocumentFactory(MakeShareable(new FStateMachineGraphTabFactory(Editor)));

	FApplicationMode::RegisterTabFactories(InTabManager);
}

void FStandardStateMachineEditorApplicationMode::AddTabFactory(FCreateWorkflowTabFactory FactoryCreator)
{
	if (FactoryCreator.IsBound())
	{
		StardardTabFactories.RegisterFactory(FactoryCreator.Execute(StateMachineEditor.Pin()));
	}
}

void FStandardStateMachineEditorApplicationMode::RemoveTabFactory(FName TabFactoryID)
{
	StardardTabFactories.UnregisterFactory(TabFactoryID);
}

void FStandardStateMachineEditorApplicationMode::PostActivateMode()
{
	StateMachineEditor.Pin()->InvokeStateMachineGraphTab();
}

创建细节面板页签工厂类

细节面板的Slate可使用PropertyEditorModule.CreateDetailView()接口,通过SetObject()设置要显示细节的对象。该工厂类需要在编辑模式类中注册到Editor中。
//StateMachineEditorTabFactories.h:

// 生成类的细节面板
struct FStateMachineDetailsTabFactory : public FWorkflowTabFactory
{
public:
	FStateMachineDetailsTabFactory(TSharedPtr<class FStateMachineEditor> InStateMachineEditor);
	virtual TSharedRef<SWidget> CreateTabBody(const FWorkflowTabSpawnInfo& Info) const override;
	virtual FText GetTabToolTipText(const FWorkflowTabSpawnInfo& Info) const override;

protected:
	TWeakPtr<FStateMachineEditor> StateMachineEditor;
};

//StateMachineEditorTabFactories.cpp:

FStateMachineDetailsTabFactory::FStateMachineDetailsTabFactory(TSharedPtr<class FStateMachineEditor> InStateMachineEditor)
	: FWorkflowTabFactory(FName("Details"), InStateMachineEditor)
	, StateMachineEditor(InStateMachineEditor)
{
	TabLabel = LOCTEXT("DetailsLabel", "Details");
	TabIcon = FSlateIcon(FEditorStyle::GetStyleSetName(), "Kismet.Tabs.Components");
	bIsSingleton = true;
	ViewMenuDescription = LOCTEXT("DetailsView", "Details");
	ViewMenuTooltip = LOCTEXT("DetailsView_ToolTip", "Show the details view");
}

TSharedRef<SWidget> FStateMachineDetailsTabFactory::CreateTabBody(const FWorkflowTabSpawnInfo& Info) const
{
	// 创建细节面板
	FStateMachineEditor* Editor = StateMachineEditor.Pin().Get();
	FPropertyEditorModule& PropertyEditorModule = FModuleManager::GetModuleChecked<FPropertyEditorModule>("PropertyEditor");
	FDetailsViewArgs DetailsViewArgs(false, false, true, FDetailsViewArgs::HideNameArea, false);
	DetailsViewArgs.NotifyHook = Editor;
	DetailsViewArgs.DefaultsOnlyVisibility = EEditDefaultsOnlyNodeVisibility::Hide;
	TSharedRef<IDetailsView> DetailsView = PropertyEditorModule.CreateDetailView(DetailsViewArgs);
	DetailsView->SetObject(Editor->GetStateMachine());
	//DetailsView->SetIsPropertyEditingEnabledDelegate(FIsPropertyEditingEnabled::CreateSP(Editor, &FStateMachineEditor::IsPropertyEditable));
	//DetailsView->OnFinishedChangingProperties().AddSP(Editor, &FStateMachineEditor::OnFinishedChangingProperties);

	return 		
		SNew(SVerticalBox)
		+ SVerticalBox::Slot()
		.FillHeight(1.0f)
		.HAlign(HAlign_Fill)
		[
			DetailsView
		];

}

FText FStateMachineDetailsTabFactory::GetTabToolTipText(const FWorkflowTabSpawnInfo& Info) const
{
	return LOCTEXT("DetailsTabTooltip", "The details tab allows editing of the properties");
}

最后可以打开资源,就会打开对应的编辑器,并创建一个显示StateMachine类的细节面板。
UE4自定义资源和编辑器(二):创建自定义编辑器

总结:

  • 需要创建一个自定义编辑器类,并在自定义资源的AssetTypeActions中打开资源时创建和初始化。
  • 创建一个编辑器模式类,用于设定布局,注册Tab工厂。
  • 需要什么Tab就创建对应的Tab工厂类,并在编辑器模式类中注册到Editor的TabManager中。
上一篇:ue4的深入


下一篇:UE4 C++工程以Game模式启动