UE4自定义资源编辑器开发-流程图表

UE4自定义资源编辑器开发-流程图表

1 Overview


在UE4开发中,图表显示是非常重要的一环,如:

  • 蓝图事件图表

  • 蓝图函数图表

  • 行为树图表


2 关键类

若要在编辑器中添加一个图表显示,则需要派生以下两个类:

  • UEdGraphSchema : 用于控制图表中的一系列操作:如创建图表中的节点,右键事件等等。

  • UEdGraph : 图表类,控制并存放所有图表内数据。

例:

class UEdGraphSchema_Test : public UEdGraphSchema
{
	GENERATED_UCLASS_BODY()
	//~ Begin EdGraphSchema Interface
	virtual void CreateDefaultNodesForGraph(UEdGraph& Graph) const override;
	virtual void GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const override;
	virtual void GetContextMenuActions(class UToolMenu* Menu, class UGraphNodeContextMenuContext* Context) const override;
	virtual const FPinConnectionResponse CanCreateConnection(const UEdGraphPin* A, const UEdGraphPin* B) const override;
	virtual const FPinConnectionResponse CanMergeNodes(const UEdGraphNode* A, const UEdGraphNode* B) const override;
	virtual FLinearColor GetPinTypeColor(const FEdGraphPinType& PinType) const override;
	virtual int32 GetNodeSelectionCount(const UEdGraph* Graph) const override;
	virtual bool IsCacheVisualizationOutOfDate(int32 InVisualizationCacheID) const override;
	virtual int32 GetCurrentVisualizationCacheID() const override;
	virtual void ForceVisualizationCacheClear() const override;
	virtual TSharedPtr<FEdGraphSchemaAction> GetCreateCommentAction() const override;
	//~ End EdGraphSchema Interface
};

class UTestGraph : public UEdGraph
{
	GENERATED_UCLASS_BODY()

public:
	//Root Node
	...
};

图表Schema类很重要,如图表里右键后生成的内容都需要在该类中控制


3 页签工厂类


同样,需要在编辑器里添加一个图表页签,则需要有一个对应的工厂类,对于这种复杂类型页签,可通过内置的 FDocumentTabFactoryForObjects 类派生出页签工厂类,该类与FDocumentTracker 配合使用,FDocumentTracker 类是用于管理所有注册的页签,若存在多个图表需要维护,则可以该类来管理这些页签的状态。

struct FTestGraphEditorSummoner : public FDocumentTabFactoryForObjects<UEdGraph>
{
public:
	DECLARE_DELEGATE_RetVal_OneParam(TSharedRef<SGraphEditor>, FOnCreateGraphEditorWidget, UEdGraph*);
	FTestGraphEditorSummoner(TSharedPtr<class FTestEditor> InTestEditorPtr, FOnCreateGraphEditorWidget CreateGraphEditorWidgetCallback);
	virtual void OnTabActivated(TSharedPtr<SDockTab> Tab) const override;
	virtual void OnTabRefreshed(TSharedPtr<SDockTab> Tab) const override;
protected:
	virtual TAttribute<FText> ConstructTabNameForObject(UEdGraph* DocumentID) const override;
	virtual TSharedRef<SWidget> CreateTabBodyForObject(const FWorkflowTabSpawnInfo& Info, UEdGraph* DocumentID) const override;
	...
};

内置的SGraphEditor可直接用于持有并操作图表类,可直接创建该类来作为页签体。

TSharedRef<SGraphEditor> FTestEditor::CreateGraphEditorWidget(UEdGraph* InGraph)
{
	check(InGraph != NULL);
	CreateCommandList();
	SGraphEditor::FGraphEditorEvents InEvents;
	InEvents.OnSelectionChanged = SGraphEditor::FOnSelectionChanged::CreateSP(this, &FTestEditor::OnSelectedNodesChanged);
	InEvents.OnNodeDoubleClicked = FSingleNodeEvent::CreateSP(this, &FTestEditor::OnNodeDoubleClicked);
	InEvents.OnTextCommitted = FOnNodeTextCommitted::CreateSP(this, &FTestEditor::OnNodeTitleCommitted);

	// Make title bar
	TSharedRef<SWidget> TitleBarWidget =
		SNew(SBorder)
		.BorderImage(FEditorStyle::GetBrush(TEXT("Graph.TitleBackground")))
		.HAlign(HAlign_Fill)
		[
			SNew(SHorizontalBox)
			+ SHorizontalBox::Slot()
		.HAlign(HAlign_Center)
		.FillWidth(1.f)
		[
			SNew(STextBlock)
			.Text(LOCTEXT("TestGraphLabel", "Test"))
		.TextStyle(FEditorStyle::Get(), TEXT("GraphBreadcrumbButtonText"))
		]
		];

	// Make full graph editor
	const bool bGraphIsEditable = InGraph->bEditable;
	return SNew(SGraphEditor)
		//.AdditionalCommands(GraphEditorCommands)
		.IsEditable(this, &FTestEditor::InEditingMode, bGraphIsEditable)
		.Appearance(this, &FTestEditor::GetGraphAppearance)
		.TitleBar(TitleBarWidget)
		.GraphToEdit(InGraph)
		.GraphEvents(InEvents);
}

以上代码会创建一个图表编辑器,开发者还需要创建一个图表实体,并通过 SGraphEditor 来操作实体。

接下来需要创建图表实体,可直接调用以下内置FBlueprintEditorUtils中的方法来实现:


/**
* Creates a new empty graph.
*
* @param	ParentScope		The outer of the new graph (typically a blueprint).
* @param	GraphName		Name of the graph to add.
* @param	SchemaClass		Schema to use for the new graph.
*
* @return	null if it fails, else.
*/
static class UEdGraph* CreateNewGraph(UObject* ParentScope, const FName& GraphName, TSubclassOf<class UEdGraph> GraphClass, TSubclassOf<class UEdGraphSchema> SchemaClass);

通过以上方法创建图表实体后,配合 FDocumentTracker 类来生成页签,如下:

void FTestEditor::InitEditor(const EToolkitMode::Type Mode, const TSharedPtr< class IToolkitHost >& InitToolkitHost, UObject* InObject)
{
	...
	if (!DocumentManager.IsValid())
	{
		DocumentManager = MakeShareable(new FDocumentTracker);
		DocumentManager->Initialize(ThisPtr);
		TSharedRef<FDocumentTabFactory> GraphEditorFactory = MakeShareable(new FTestGraphEditorSummoner(ThisPtr,
			FTestGraphEditorSummoner::FOnCreateGraphEditorWidget::CreateSP(this, &FTestEditor::CreateGraphEditorWidget)
		));
		DocumentManager->RegisterDocumentFactory(GraphEditorFactory);	
	}
	...
}

通过 FDocumentTracker 类注册并打开页签,如下:


MyGraph = FBlueprintEditorUtils::CreateNewGraph(TestObject, TEXT("Test Graph"), UTestGraph::StaticClass(), 
TSharedRef<FTabPayload_UObject> Payload = FTabPayload_UObject::Make(MyGraph);
TSharedPtr<SDockTab> DocumentTab = DocumentManager->OpenDocument(Payload, bNewGraph ? FDocumentTracker::OpenNewDocument : 
FDocumentTracker::RestorePreviousDocument);

OpenDocument函数会找到已注册的页签工厂类,并调用 CreateTabBodyForObject 函数来创建页签体,也可以参考FBehaviorTreeEditor::RestoreBehaviorTree() 中的实现。

注意也可以不使用 FDocumentTabFactoryForObjects类型工厂,自己定义工厂类来创建图表页签也是可以的。

上面示例中的 CreateTabBodyForObject 用于调用 CreateGraphEditorWidget 方法来创建页签体。

TSharedRef<SWidget> FTestGraphEditorSummoner::CreateTabBodyForObject(const FWorkflowTabSpawnInfo& Info, UEdGraph* DocumentID) const
{
	return OnCreateGraphEditorWidget.Execute(DocumentID);
}

最后生成的图表如下。

GraphView


链接




Tags: UE4 Editor Vistied:
Share: Twitter Facebook LinkedIn