UE4 Asset Editor Graph View

UE4 Asset Editor Graph View

1 Overview

Graph view is very important in UE4 development, it can make development conveniently. For example:

  • Blueprint Event Graph

  • Blueprint Function Graph

  • Behavior Tree

2 Critical Class

To creat a graph view in UE4, you’ll need to derive from two basic classes.

  • UEdGraphSchema : This class determines a number of operations in graph, such as creating node, contextmenu action and so on.

  • UEdGraph : This class contain all graph data you need.

class UEdGraphSchema_Test : public UEdGraphSchema
	//~ 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

	//Root Node

3 Tab Factory

The build-in SGraphEditor is the widget that used to hold and edit graph.

TSharedRef<SGraphEditor> FTestEditor::CreateGraphEditorWidget(UEdGraph* InGraph)
	check(InGraph != NULL);
	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 =
			+ SHorizontalBox::Slot()
			.Text(LOCTEXT("TestGraphLabel", "Test"))
		.TextStyle(FEditorStyle::Get(), TEXT("GraphBreadcrumbButtonText"))

	// Make full graph editor
	const bool bGraphIsEditable = InGraph->bEditable;
	return SNew(SGraphEditor)
		.IsEditable(this, &FTestEditor::InEditingMode, bGraphIsEditable)
		.Appearance(this, &FTestEditor::GetGraphAppearance)

You can create a graph and use the above SGraphEditor to hold it, and add a tab factory to create tab body as follow.

  • Create a tab factory class derived form FDocumentTabFactoryForObjects.

  • Using the build-in class FDocumentTracker to manage these graph tabs.

struct FTestGraphEditorSummoner : public FDocumentTabFactoryForObjects<UEdGraph>
	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;
	virtual TAttribute<FText> ConstructTabNameForObject(UEdGraph* DocumentID) const override;
	virtual TSharedRef<SWidget> CreateTabBodyForObject(const FWorkflowTabSpawnInfo& Info, UEdGraph* DocumentID) const override;

FDocumentTracker is a build-in class to manage all the registered tabs. For example, there are serveral graph tabs and you can find all the tabs at runtime in this manager class.

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

Create a graph using FBlueprintEditorUtils as follow.

* 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);

Create a tab by the manager created above(FDocumentTracker).

TSharedRef<FTabPayload_UObject> Payload = FTabPayload_UObject::Make(MyGraph);
TSharedPtr<SDockTab> DocumentTab = DocumentManager->OpenDocument(Payload, bNewGraph ? FDocumentTracker::OpenNewDocument : FDocumentTracker::RestorePreviousDocument);

OpenDocument function will find the registerd tab factory and call CreateTabBodyForObject function of your tab factory class to spawn tab widget. You can find an example of these implementation in FBehaviorTreeEditor::RestoreBehaviorTree().

Here, CreateTabBodyForObject of my test tab factory class is to pass the graph pointer to a callback function (CreateGraphEditorWidget above).

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

A graph view is given below.


Tags: UE4 Editor Vistied:
Share: Twitter Facebook LinkedIn