Connect C++ to UMG Blueprints with BindWidget

How to control logic from C++ and configure visuals in Blueprints.

One of the most common questions you'll have if you start making C++-based UIs is this:

How can I control Blueprint-created widgets from C++?

The answer to this is the BindWidget meta property.

Basic BindWidget example

Connecting C++ to Blueprints through BindWidget.

UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
class UTextBlock* ItemTitle;

While it's not mentioned on the UPROPERTY() wiki page or any of the other documentation, it's one of the most useful tags for you as a UI developer.

By marking a pointer to a widget as BindWidget, you can create an identically-named widget in a Blueprint subclass of your C++ class, and at run-time access it from the C++.

Here's a step-by-step process to getting a test working:

  1. Create a C++ subclass of UUserWidget.
  2. In it add a member variable of type UWidget*, or the UWidget subclass that you wish to access from C++ (UImage, UTextBlock etc.)
  3. Mark it with UPROPERTY(meta=(BindWidget)).
  4. Run the editor and create a Blueprint subclass of your C++ class.
  5. Create a widget with the same type and exact name as your member variable.
  6. You can now access the widget from C++.

If any of these don't make sense, check out my introductory series on making UIs with Unreal.

Example Code

BindExample.h

Header file for our bind example.

#pragma once 

#include "BindExample.generated.h"

UCLASS(Abstract)
class UBindExample : public UUserWidget
{
	GENERATED_BODY()

public:
	virtual void NativeConstruct() override;

	UPROPERTY(BlueprintReadOnly, meta = (BindWidget))
	class UTextBlock* ItemTitle = nullptr;
};
BindExample.cpp

In the body we can also reference the property

#include "BindExample.h"
#include "Components/TextBlock.h"

void UBindExample::NativeConstruct()
{
	// Call the Blueprint "Event Construct" node
	Super::NativeConstruct();

	// ItemTitle can be nullptr if we haven't created it in the
	// Blueprint subclass
	if (ItemTitle)
	{
		ItemTitle->SetText(TEXT("Hello world!"));
	}
}

Now compile the C++ and open up your Blueprint subclass of the C++ class where you added ItemTitle. If you compile your Blueprint, you will be shown an error if there is no TextBlock widget named ItemTitle inside your UserWidget.

Pros & Cons of BindWidget

  • Easier to maintain complex logic in C++. No spaghetti-fighting in Blueprints.
  • Easier for collaboration, no worries about locking Blueprint assets.
  • Requires re-compile to see changes.
  • Can be harder for non-programmers to see how data is being populated.

Optional Widgets

If you want to make the widget optional, instead use meta=(BindWidgetOptional). With this there will be no error shown if the Blueprint class does not have a widget with that name.

BindWidgetOptional example
UPROPERTY(BlueprintReadWrite, meta = (BindWidgetOptional))
UTextBlock* ItemTitle;

Quirks of BindWidget

  • Even if you don't mark the widget as optional in your property tags, you can still run your game with a Blueprint subclass that has not defined a matching widget. So you should generally do nullptr checks.
  • Normally when ticking the "Is Variable" flag on a UserWidget would make it available in the Graph tab of the editor. However, if there is a property with that name, marked as BindWidget, the only way to make it accessible in the blueprint is add BlueprintReadOnly or BlueprintReadWrite to its UPROPERTY() tag.
  • By default, variables defined in a parent C++ class are only shown in the Variables list if "Show Inherited Variables" is checked (see screenshot).
  • Widgets marked with BindWidget are null in the C++ constructor, they are initialized later on in the lifecycle. If you need to do constructor-like setup use the NativeConstruct() function.

How to show variables defined in a parent C++ class.

What next?