Blueprint node has a clean UI by default.
However, some Blueprint nodes provide own UI that users can use easier than default.
For example, the Blueprint node "Switch on Int" has a horizontal bar above the default execution pin.
This makes it easier to distinguish from conditional execution pin.
In this article, we will modify the UI of the Blueprint node created in the Menu article.
- Create Your Own Blueprint Node by Inheriting K2Node (1) Basic
- Create Your Own Blueprint Node by Inheriting K2Node (2) Execution Pin
- Create Your Own Blueprint Node by Inheriting K2Node (3) Menu
- Create Your Own Blueprint Node by Inheriting K2Node (4) UI <— This article
目次
Source Code
The complete source code is available on GitHub.
https://github.com/colory-games/techblog-sample-projects/tree/main/nutti/20220815
To run the source code, follow these steps.
- Place the directory
MyManualSwitch
intoPlugins
in your Unreal Engine project directory. - Right click on the
.uproject
file and create a project file for Visual Studio. - Open the project file and build the project.
- Run Unreal Engine from the
.uproject
file and activate the "MyManualSwitch" plugin.
UI Changes
Here is the modified UI for the Blueprint node "MyManualSwitch".
You can see that a new horizontal bar and text that displays an execution destination, have been added below the execution pin on the input side.
Notice also that the text changes when the execution destination changes.
Create a Module
Create a module by following to the description in the Basic section.
For the concreate instructions to create a module, please refer to the article for the basic.
Change the UI of Blueprint Node
To change the UI of a Blueprint node, follow the below steps.
- Inherit from class
SGraphNodeK2Base
- Configure basic information
- Define the UI construction procedure
- Associate the UI with the Blueprint node
1. Inherit from Class SGraphNodeK2Base
First define the class SGraphNodeMyManualSwitch
, which extends the class SGraphNodeK2Base
.
class SGraphNodeMyManualSwitch : public SGraphNodeK2Base
{
SLATE_BEGIN_ARGS(SGraphNodeMyManualSwitch)
{
}
SLATE_END_ARGS()
void Construct(const FArguments& InArgs, UK2Node_MyManualSwitch* InNode);
virtual void CreatePinWidgets() override;
};
The macro SLATE_BEGIN_ARGS
and SLATE_END_ARGS
define the specification of parameters that can be passed at the instatiation time.
But, we do not use them in this case.
The class SGraphNodeMyManualSwitch
has two member functions.
Member Function Name | Role |
---|---|
Construct |
Called at instantiation time. Configure basic information here. |
CreatePinWidgets |
Called when the Engine draw input/output pins. The construction process of UI need to be defined here. |
2. Configure Basic Information
Basic information can be configured by defining a configuration process in the member function Construct
of class SGraphNodeMyManualSwitch
.
void SGraphNodeMyManualSwitch::Construct(const FArguments& InArgs, UK2Node_MyManualSwitch* InNode)
{
GraphNode = InNode;
SetCursor(EMouseCursor::GrabHand);
UpdateGraphNode();
}
GraphNode
is a member variable defined in the parent class and will be used later to define the construction process of the UI.
It is common to assign the argument InNode
.
Next, call the member function SetCursor
to change the cursor to a hand icon when the mouse over a Blueprint node.
Note that the cursor icon can be changed depending on the value of the enumerated type EMouseCursor
passed to the member function SetCursor
.
Finally, call the member function UpdateGraphNode
to notify that the UI of Blueprint node has been changed.
3. Define the UI Construction Procedure
Define the construction process of the UI by overriding the member function CreatePinWidgets
of class SGraphNode
.
The UI is constructed according to the Unreal Engine’s Slate UI Framework.
void SGraphNodeMyManualSwitch::CreatePinWidgets()
{
UK2Node_MyManualSwitch* MyManualSwitch = CastChecked(GraphNode);
// Add pin UI.
for (auto It = GraphNode->Pins.CreateConstIterator(); It; ++It)
{
UEdGraphPin* Pin = *It;
if (!Pin->bHidden)
{
TSharedPtr NewPin = FNodeFactory::CreatePinWidget(Pin);
check(NewPin.IsValid());
AddPin(NewPin.ToSharedRef());
}
}
bool bExecuteA = MyManualSwitch->GetSwitchValue();
// Add horizontal bar.
LeftNodeBox->AddSlot()
.AutoHeight()
.HAlign(HAlign_Left)
.VAlign(VAlign_Center)
[
SNew(SImage)
.Image(FEditorStyle::GetBrush("Graph.Pin.DefaultPinSeparator"))
];
// Add text.
LeftNodeBox->AddSlot()
.AutoHeight()
.HAlign(HAlign_Left)
.VAlign(VAlign_Center)
.Padding(10.0f, 5.0f)
[
SNew(STextBlock)
.Text(FText::FromString(bExecuteA ? "Execute A" : "Execute B"))
];
}
We will not discuss the Slate UI framework in detail here, but explain two important things.
Add Pins
New pin can be created with the member function CreatePinWidget
of class FNodeFactory
.
Then, it can be added to the UI of a Blueprint node by calling the member function AddPin
.
These member functions are the easiest way to implement if you use the default UI.
The member function AddPin
automatically determines the location of the UI to be added based on the input/output of the pin.
LeftNodeBox
To add the UI to the left side of the Blueprint node, we add the horizontal bar and the text to the member variable LeftNodeBox
.
To add the UI to the right side of the Blueprint node, we need to manipulate the member variable RightNodeBox
.
Thus, if you want to change the UI for a Blueprint node, you need to manipulate the member variable LeftNodeBox
or RightNodeBox
.
4. Associate the UI with the Blueprint Node
Finally, associate a Blueprint node (class UK2Node_MyManualSwitch
) with the UI defined in class SGraphNodeK2Base
.
This process can be done by adding the corresponding process to the member function FMyManualSwitchModule::StartupModule
, which is executed on the module loading phase.
void FMyManualSwitchModule::StartupModule()
{
GraphPanelNodeFactory_MyManualSwitch = MakeShareable(new FGraphPanelNodeFactory_MyManualSwitch());
FEdGraphUtilities::RegisterVisualNodeFactory(GraphPanelNodeFactory_MyManualSwitch);
}
This time, we define the class FGraphPanelNodeFactory_MyManualSwitch
and pass its instance to the member function FEdGraphUtilities::RegisterVisualNodeFactory
.
The definition of class FGraphPanelNodeFactory_MyManualSwitch
is shown below.
class FGraphPanelNodeFactory_MyManualSwitch : public FGraphPanelNodeFactory
{
virtual TSharedPtr CreateNode(UEdGraphNode* Node) const override
{
if (UK2Node_MyManualSwitch* MyManualSwitch = Cast(Node))
{
return SNew(SGraphNodeMyManualSwitch, MyManualSwitch);
}
return nullptr;
}
};
Inherits class FGraphPanelNodeFactory
and overrides member function CreateNode
.
The member function CreateNode
has a argument that is the Blueprint node inherited from class UEdGraphNode
.
So, we need to check if the blueprint node is a UK2Node_MyManualSwitch
or not.
In it is UK2Node_MyManualSwitch
, we call SNew
to instantiate SGraphNodeMyManualSwitch
.
We can find the customized UI will be displayed when a user add UK2Node_MyManualSwitch
which calls SGraphNodeMyManualSwitch
.
The custom UI must be unassociated when the module is unloaded.
void FMyManualSwitchModule::ShutdownModule()
{
if (GraphPanelNodeFactory_MyManualSwitch.IsValid())
{
FEdGraphUtilities::UnregisterVisualNodeFactory(GraphPanelNodeFactory_MyManualSwitch);
GraphPanelNodeFactory_MyManualSwitch.Reset();
}
}
Use the Created Node
Let’s use the node you created.
Open the Blueprint Editor, right-click to display the menu, and enter "mymaualswitch" in the search box.
Select and place the node "MyManualSwitch" in the category "Flow Control".
If you right-click on a Blueprint node and change the execution destination, the text will be changed according to the current execution destination.