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.

Example UUserWidget Subclass

This sample is the most basic, empty "hello world" example User Widget we can create. We will add functionality to it later.

ExampleWidget.h

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#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()

protected:
	// Doing setup in the C++ constructor is not as
	// useful as using NativeConstruct.
	virtual void NativeConstruct() override;
};

ExampleWidget.cpp

#include "ExampleWidget.h"

void UExampleWidget::NativeConstruct()
{
	Super::NativeConstruct();

	// Here is where I typically bind delegates,
	// and set up default appearance
}

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 Blueprint

Under All Classes search for ExampleWidget.

Note: The industry-standard style guide for Unreal Engine recommends prefixing User Widget Blueprints with WBP_. I also personally like prefixing C++ UserWidget subclasses with UW.

Changing the parent class of an existing Blueprint

Alternatively, we can change the parent of an existing UserWidget Blueprint. Open your Blueprint, then from the menu at the top chooose File > Reparent Blueprint. In the popup window choose your ExampleWidget class.

Reparent an existing 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!

Blueprint's parent class is shown in the top-right

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

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

Blueprints or C++?

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.

ExampleWidget.h

// 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;
};

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.

Posted:

Updated: