Introduction

UMG (Unreal Motion Graphics UI Designer) is a very powerful framework for creating User Interface in Unreal Engine 4. The Visual Editor allows for logical and hierarchical positioning of predefined elements to be combined in a Widget. These elements like SButton are mainly based on Slate – a predecessor of UMG. While composing elements for a simple UserWidget is convenient, building a set of similar UserWidgets is not. Every complex structure needs to be copied over, together with Blueprint logic. To cope with this problem, one can create his own Slate control, but finding proper resources for learning and managing the element strictly from code is not a trivial task. Fortunately there is an easier solution – building UserWidget control for UserWidgets! This article will show how to prepare UserWidget to be a building block with as little C++ code as possible.

What will you gain?

Here are several pros that you get using proposed approach.

Predictable and stable behavior

Implementation for every control – be it a menu element, button, image, layout composition – will be created once and every problem that can occur will occur inside that implementation. This will allow for faster bug resolving and having it resolved for every instance at the same time. The same thing concerns adding new features.

Cleaner Blueprints

One of the main problem with Blueprints is connections spaghetti which very soon makes it unreadable. Delegating as much of the implementation as you can to other Blueprints is more than desirable.

Cleaner UserWidget’s Hierarchy

Having e.g. Text hidden inside of Button’s implementation to make TextButton makes the hierarchy more clean (as long as you keep proper level of abstraction).

Assets ready for another project

Properly built building blocks will be easily transferable to other projects and will require little work to fit them to the projects style. You can even make a plugin with them and put it in the marketplace.

Prerequisities

Skill

A basic knowledge about UE4 and UMG would be desirable. C++ code will be used but one should make it through using information inside this article.

Software

Unreal Engine

This tutorial was created in UnrealEngine 4.12.5. You can obtain UE4 from official website.

Microsoft Visual Studio

We will use the code very sparingly but it is a must in this solution so you need to obtain free Visual Studio 2015 Community Edition from here.

Operating System

You will need a Windows 7 or higher (this solution uses Windows 10).

Example project

You can find the Unreal Engine 4 project here. You will need to run the TextButtonTest.uproject file and later compile the code to prepare the game to be run.

Hardware

Any PC capable of running UE4 will be suitable.

Configuration

Creating new project

First we will need to create a basic project. Let us start with Basic Code. Code part will be needed for enabling some features which are normally not available in UserWidget Blueprint.

Open Unreal Engine 4 Editor, go to File -> New Project, select C++ tab and a Basic Code. Let’s name it TextButtonTest.

newproject.png

Now project will be prepared and compiled after which it should open in editor.

newprojectineditor.PNG

Creating custom GameMode, HUD and Widget

To start we need to configure project to accept our future Widgets.

Click Add New in Content Browser and select Blueprint Class. Next select GameMode in Pick Parent Window and call it BP_SimpleGameMode. Now repeat the process but now in Pick Parent Window select All classes and search for HUD.

creatinghud.PNG

Pick it and name BP_SimpleHUD.

Next repeat the proces but pick UserWidget in Pick Parent Window.

You should now have 3 Blueprints in Content folder.

bpcreated.PNG

Replacing default GameMode and setting custom HUD

In the World Settings of Editor you can find a GameMode category.

defaultgamemode.PNG

Change the GameModeOverride to previously created BP_SimpleGameMode. Changing HUD Class will now be enabled. Select BP_SimpleHUD.

customgamemodeandhud.PNG

Saving map

Before doing more changes lets save our map, which is currently named Untitled. Click CTRL+S and a Save Level As dialog will open call it SimpleMap and click Save.

savelevelas.PNG

Setting HUD to be displayed on start

For now we configured Editor to be ready to use our custom classes, but we need to tell it when to use them.

Open the BP_SimpleGameMode and click Event Graph. Here we will tell the Engine to view our HUD on game start.

Drag an execution connection from the BeginPlay event and search for SetInputModeUIOnly. Having it placed drag a connection from Target parameter of SetInputModeUIOnly and select GetPlayerController. Finally drag an execution connection from SetInputModeUIOnly and select SetShowMouseCursor. Toggle the ShowMouseCursor so it is enabled.

gamemodeeventgraph1.PNG

In Widget to Focus was not set because we only want Engine to show the HUD. Now let’s go to BP_SimpleHUD and make our BP_SimpleWidget to be shown.

Open BP_SimpleHUD, go to Event Graph and drag an execution connection from BeginPlay event. Select CreateWidget. In Class parameter dropdown select our BP_SimpleWidget. Connect a GetOwningPlayerController to Owning Player parameter. Now drag an execution connection from Create BP Simple Widget Widget and select Add to Viewport. Connect the output of Create BP Simple Widget Widget to the Target parameter of Add to Viewport.

hudeventgraph1.PNG

Having that set up we only need anything to be drawn on BP_SimpleWidget to be sure that it is working.

Go to BP_SimpleWidget, grab Text from Palette menu and place it on Canvas, in the left upper corner. Change the Content->Text property of just placed TextBlock to SimpleText.

widgetsimplepomazany.PNG

Test run the game

With having everything set, running the game should end up with UI enabled and having SimpleText drawn in the left upper corner of Viewport.

Click Play in the Editor main Window and hopefully you will end up with the screen similar to the one on the image below.

testrun.PNG

Creating TextButton UserWidget

Time for the clue of this article! A UserWidget that is planned to be a control for another UserWidget.

Create a new UserWidget Blueprint and name it BP_TextButtonWidget. Open it, remove default Canvas Panel from hierarchy and add a Button and a Text inside of it.

textbutton1.PNG

Button seems to be overwhelmingly big, but having it as the root will allow us to easily manipulate it’s size when manipulating it in another container.

Now open BP_SimpleWidget and scroll down in the Palette menu to the bottom. You’ll find User Created category. It is likely that it will already contain some widgets from plugins. Try to find our Widget – the BP_TextButtonWidget.

paletteourwidget.PNG

Now drag BP_TextButtonWidget onto the Canvas Panel. IT should look like similar to the image below:

draggedourwidget.PNG

UserWidget control out of the box downfalls

That’s something! We have our UserWidget as a child of a bigger container UserWidget. But the obvious part ends here. There are several features that we lack:

Changing UserWidget’s children properties

All specific properties of BP_TextButtonWidget are hidden and cannot be accessed from the Designer. We only have properties of the UserWidget as a whole.

Live update of changed properties

This problem is not visible yet, but I’d like to point it out already. After adding properties for changing the BP_TextButtonWidget look (e.g. the displayed text) it will not update in the Designer (it can work on the game start if hooked to Construct Event). We need to address this problem to make Widget work in the Designer as it is expected.

Defining events for UserWidget

As mentioned earlier we don’t have access to properties of UserWidget children. It also adresses Events. It is likely that we’d like to have access to OnClick Event from TextButton UserWidget. We need to define that Event explicitly and link it inside the UserWidget.

Making TextButton UserWidget behave as a control

Expose Text properties in the TextButton UserWidget’s API

We would like to expose TextBlock’s Font Size and Text. We need to create that variables, make them Editable and bind them to correct properties of TextBlock.

Go to BP_TextButtonWidget and open EventGraph. Create a Text variable of type Text with default value SimpleTextButton and FontSize variable of type Integer with default value of 24. Set their category to TextBlock and mark them to be Editable. You should end up with something similar to this image.

varaibles.PNG

Compile it and open the BP_SimpleWidget. Select BP Text Button Image from the Herarchy and ensure that you can find our newly created variables.

editablevariablespomazany.PNG

Changing their values will do nothing because we didn’t hook them up in BP_TextButtonWidget. We could bind the Text variable to TextBlock’s Text but it will only work on Contruct Event ergo changes will not be visible in the Editor. Font Size cannot be bound this way so this approach wouldn’t work. We need our UserWidget to update all it’s variables on demand. We need to implement SynchronizeProperties.

Synchronize variables

Creating TextButtonWidget C++ class

Note
This solution is an improved solution from 
https://wiki.unrealengine.com/UMG_Previewing_custom_UserWidgets_in_realtime

Unfortunately this can only be done using C++ because SynchronizeProperties is not exposed to Blueprint. Let us create a UUserWidget derived class. Open main Editor Window, select Add New and pick New C++ Class. In the Wizard find UserWidget.

userwidgetclasswizard.PNG

Click Next and name it TextButtonWidget. Finally click Create Class.

wizardcreate.PNG

Compilation will conclude. After that UE4 should open Visual Studio on the newly created class.

afterclasscreation.PNG

Writing Synchronization logic

We could write all the Widget’s logic in C++ but I would like to keep this article as much Blueprint based as possible. We will only write logic for enabling Synchronization.

Open TextButtonWidget.h and add these lines below GENERATED_BODY() macro.

public:
 //overrides
 virtual void SynchronizeProperties() override;

/**
 * This is called after a widget is constructed and properties are synchronized.
 * It can also be called by the editor to update modified state.
 * Override this event in blueprint to update the widget after a default 
 * property is modified.
 */
 UFUNCTION(BlueprintImplementableEvent, Category = "User Interface")
 void OnSynchronizeProperties();

We here declare that we will override the SynchronizeProperties implementation so we can add our own code. Our goal is to call the OnSynchronizeProperties() function which will be defined in BlueprintTextButtonWidget.h should look like this:

utextbuttonh.PNG

Don’t worry about the red marks. UE4 is often too heavy for Visual Studio to view code problems correctly.

Now open TextButtonWidget.cpp and add this code below #include “MenuButtonWidget.h”:

void UMenuButtonWidget::SynchronizeProperties() {
 Super::SynchronizeProperties();
 OnSynchronizeProperties();
}

The SynchronizeProperties() definition calls it’s implementation from the parent so it works as intended and after that adds the call to our OnSynchronizeProperties(). Because OnSynchronizeProperties() is marked with BlueprintImplementableEvent macro we can leave the implementation to Blueprint specifically. Code for TextButtonWidget.cpp should look like this:

afterclasscreationcpp.PNG

Now click right mouse button on TextButtonTest project in Solution Explorer and run Build.

buildpomazany.png

Project should build without any errors. If the Output is similar to the one on the image, we can go back to Unreal Editor.

output.PNG

Hooking C++ code to Blueprint

Open BP_TextButtonWidget, click File and select ReparentBlueprint.

reparent.png

From the popup window select TextButtonWidget.

reparent2.png

Open EventGraph and add a OnSynchronizeProperties Event node.

onsynchronizenode.png

Blueprint logic for Synchronizing exposed variables

Now we can finally connect our exposed variables: Text and FontSize.

First go to the Designer of BP_TextButtonWidget and make TextBlock to be a variable so we can reference it in EventGraph.

referencetextblockpomazany.PNG

Go back to EventGraph. Let us start with a Sequence to logically divide nodes affected by exposed parameters.

On the Then0 output get the reference to the TextBlock_0 and call SetText method with it’s InText parameter set to our Text variable.

blueprint1.PNG

On the Then1 output get the reference to the TextBlock_0, call GetFont and break it to unveil the objects structure. We need to create similar structure but with changed Font Size. Call MakeSlateFontInfo and connect all variables from the original structure besides the Size which should be connected to out FontSize variable. Finally call SetFont on TextBlock_0 with new structure as the parameter.

blueprint2.PNG

This is all. It will guarantee that our exposed variables will affect Widget’s state. But before we check it out let’s hook Event Construct as an alternative path to Sequence. Thanks to that UserWidget will be updated according to the exposed variables when the UserWidget is created in the game.

eventcontruct.PNG

Finally, go to BP_SimpleWidget and try to edit Text and FontSize parameters. It should instantly affect the look of our TextButton after clicking Enter.

affect.PNG

Expose the OnClick Event

Last thing that we lack to have full control over child Widget (BP_TextButtonWidget) are Events on which we can react from the container Widget(BP_SimpleWidget).

We will use EventDispatcher to enable this behavior.

Go to BP_SimpleWidget and add EventDispatcher of name OnClickEventDispatcher from the EventGraph.

eventdispatcher.PNG

Go back to BP_SimpleWidget Designer, click Button in Hierarchy menu and click + on OnClicked Event.

buttonclick.png

OnClick event for that Button will appear in the EventGraph. Now connect a Call method of OnClickEventDispatcher to it.

connecteventdispatcher.PNG

This will cause that every OnClicked event will be forwarded to the class that binds the OnClickEventDispatcher.

Let’s go back to BP_SimpleWidget. After selecting BP Text Button Widget from Hierarchy menu a OnClickEventDispatcher Event should appear.

eventonclickeventdispatcher.png

Click it. This will take us to the EventGraph. Let’s hook a Print String function to be sure that this works in game. Set the Print String’s text to “TextButton Clicked!”.

printclkicked.PNG

Go to main Editor Window and click Play. Click the button and see our text printed onto screen!

textbuttonclicked.png

Conclusion

Creating child UserWidgets to work as complex controls is a little troublesome but very powerful and it is worthwhile to create them for saving time and frustration later in the project.

What’s next?

Styling

Our TextButtonWidget does it’s work but it would be nice to have it styled differently. Unfortunately simple changing Button’s color depending on it’s state (normal, hovered, clicked) is not enough to make the Text inside of it work correctly as it will not change it’s color correspondingly. Our UserWidget needs to address it’s own problems and this is the topic of the next article.

Styling a TextButton UserWidget custom control in UMG, UE4

Advertisements