在UE4开发中,图表显示是非常重要的一环,如:
蓝图事件图表
蓝图函数图表
行为树图表
…
若要在编辑器中添加一个图表显示,则需要派生以下两个类:
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类很重要,如图表里右键后生成的内容都需要在该类中控制。
同样,需要在编辑器里添加一个图表页签,则需要有一个对应的工厂类,对于这种复杂类型页签,可通过内置的 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);
}
最后生成的图表如下。