Unreal UIs: Creating a UserWidget in C++

In the previous tutorial we showed how you can create a UserWidget Blueprint in the editor, and then why it’s a good idea to transition to a mix of C++ and Blueprints in our UI.

In this approach we will create a new C++-based subclass of UUserWidget, and then create a Blueprint subclass of that new C++ class.

Unreal UI Introduction Series

  1. An Introduction to Making UIs in Unreal
  2. Making UIs in Unreal with C++: Basics
    1. Creating C++-based UserWidgets
    2. Creating New UMG Widgets
    3. Creating New Slate Widgets (Coming soon)

Example UUserWidget Subclass

This sample is the most basic, empty “hello world” example widget we can create.

ExampleWidget.h

#pragma once

#include "ExampleWidget.generated.h"

// We make the class abstract, as we don't want to create
// instances of this, instead we want to create instances
// of our UMG Blueprint subclass.
UCLASS(Abstract)
class UExampleWidget : public UUserWidget
{
	GENERATED_BODY()

public:
	UExampleWidget(const FObjectInitializer& ObjectInitializer);

	// Optionally override the Blueprint "Event Construct" event
	virtual void NativeConstruct() override;

	// Optionally override the tick event
	virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
};

ExampleWidget.cpp

#include "ExampleWidget.h"

UExampleWidget::UExampleWidget(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
}


void UExampleWidget::NativeConstruct()
{
	// Do some custom setup

	// Call the Blueprint "Event Construct" node
	Super::NativeConstruct();
}


void UExampleWidget::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
{
	// Make sure to call the base class's NativeTick function
	Super::NativeTick(MyGeometry, InDeltaTime);

	// Do your custom tick stuff here
}

Now that you have a basic example, compile and run the editor.

We now want to create a UserWidget Blueprint class that is a subclass of our newly-created C++ class. There are two ways to do this:

  • Either we create a brand-new UserWidget
  • Or we change the parent of an existing UserWidget.

Creating a new Blueprint subclass of our C++ Class

When creating a new UserWidget, instead of using the right-click “create UserWidget” shortcut, you need to use the more general “create Blueprint shortcut. Then from the list choose your newly created ExampleWidget as the base class.

▲ Creating a new UserWidget, it's possible to pick the parent class of the new Blueprint class

Changing the parent class of an existing Blueprint

Alternatively, we can change the parent of an existing UserWidget Blueprint. On the File menu choose Reparent, then from the list choose ExampleWidget.

▲ Reparenting an existing UserWidget Blueprint

You can see the Blueprint UserWidget’s parent class in the top-right of the editor window. If it says ExampleWidget, you’re good to go!

Now we Have a C++ Base Class, Now What?

Now your Blueprint Widget has a custom parent C++ class, we will have the benefits mentioned in the previous tutorial, and also:

Tricks of the Trade

After working with UMG for a year, I can safely say one of the most tricky things to decide when you’re making a game’s UI, is how to mix C++ and Blueprints in the UI.

A game’s UI is usually one of the most frequently changed parts of the game. Prototypes and mock-ups are created and thrown away almost every month, and often it is quicker to start from scratch every time.

At first, it would seem natural to use only Blueprints for your UIs. They’re much quicker to create and test, especially if your C++ build times are particularly long.

However I found that every time I had to create a new iteration of the UI, with a new organization of widgets, I often had to rewrite significant chunks of Blueprint logic. I improved the situation somewhat by creating reusable utility classes in Blueprints, but it was still impossible to inspect data for most variable types in Blueprints.

There is a better compromise, that works quite well in my experience. It is better to put all the data-related logic in C++, and the visual logic in Blueprints.

Generally the data changes much less frequently than the UI visuals, and when refactoring systems it becomes clear how your UI struct-populating C++ code needs to be refactored. Then in the Blueprint, it is a simple matter of connecting up the struct properties to the widgets that use them.

Imagine we wanted to populate a very specific widget with a plant’s name and its icon. If the player had not discovered the plant yet, those could be replaced in the C++ with correct “unknown plant” values.

// Only contains properties that we are *sure* are needed in the UI
USTRUCT(BlueprintType)
struct FUIPlantInfo
{
	UPROPERTY(BlueprintReadOnly, Category=Plant)
	FText ShortName;
	UPROPERTY(BlueprintReadOnly, Category=Plant)
	UTexture2D* Icon = nullptr;
};

UCLASS()
class UIDataPopulator
{
	GENERATED_BODY()
public:
	// Populates a struct with all the info about the given plant.
	static void UIDataPopulator::GetPlantInfo(EPlantType Type, struct FUIPlantInfo& PlantInfo);
};

Conclusion

The next tutorial in the series covers creating a C++ subclass of UWidget, which will give us the ability to make generic reusable components that do not rely on Blueprint subclasses.

Unreal UI Introduction Series

  1. An Introduction to Making UIs in Unreal
  2. Making UIs in Unreal with C++: Basics
    1. Creating C++-based UserWidgets
    2. Creating New UMG Widgets
    3. Creating New Slate Widgets (Coming soon)