[TUTORIAL/SNIPPET] Creating a UMG Widget in C++, and delegate example

Hey everyone i just wanted to post this quik tutorial about creating widgets in C++.
For a tutorial on How to extend a UUserWidget:: for UMG in C++ see link.

Now doing this is prety straight forward except for when dealing with multiplayer.
And i spent some houers trying diferent solution and this is what i came up with.

1 In your player controller class add two new member variabels like this.



	// The class that will be used for the players Inventory UI
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Player, HUD and UI")
		TSubclassOf<class UInventoryUserWidget> InventoryUIClass;

	// The instance of the players Inventory UI Widget
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Player, HUD and UI")
		class UInventoryUserWidget* InventoryWidget;

2 Override the BeginPlay() method in your Player Controller class.


void AMyPlayerController::BeginPlay()
{
	Super::BeginPlay();

	// Only create the UI on the local machine (dose not excist on the server.)
	if (IsLocalPlayerController())
	{
		if (InventoryUIClass) // Check the selected UI class is not NULL
		{
			if (!InventoryWidget) // If the widget is not created and == NULL
			{
				InventoryWidget = CreateWidget<UInventoryUserWidget>(this, InventoryUIClass); // Create Widget
				if (!InventoryWidget )
				    return;
				InventoryWidget->AddToViewport(); // Add it to the viewport so the Construct() method in the UUserWidget:: is run.
				InventoryWidget->SetVisibility(ESlateVisibility::Hidden); // Set it to hidden so its not open on spawn.
			}
		}
	}
}

3 Open and close inventory UI example.



void AMyPlayerController::ToggleInventory()
{
	if (bShowingInvetory)
		bShowingInvetory = false;
	else
		bShowingInvetory = true;

	if (InventoryWidget)
	{
		if (bShowingInvetory)
		{
			InventoryWidget->SetVisibility(ESlateVisibility::Visible);
		}
		else {
			InventoryWidget->SetVisibility(ESlateVisibility::Hidden);
		}
	}
}

Thats it! :slight_smile:
Now if you are wondering way I don`t create it on the server, how do you have server > client behavior?
I do this by creating delegates on the Player Controller and bind them in the Contruct_Implementation() method, that in turns call a “BlueprintImplementableEvent” to notifie the widget it self so it can behave accordingly.
Note: OnPlayerPickupItem delegate is called from server to client using a Remote Procedure Call (RPC)

is a example of this.


void UInventoryUserWidget::Construct_Implementation()
{
	Super::Construct_Implementation();

	AMyPlayerController* PC = CAST_TO_MY_PC(GetOwningPlayer());
	if (PC)
	{
		// Calls CallPlayerPickupItem() that in turn calls the "BlueprintImplementableEvent" on OnPlayerPickedItem()
		PC->OnPlayerPickupItem.RemoveDynamic(this, &UInventoryUserWidget::CallPlayerPickupItem); // Remove the delegate before binding it. (Its always safe to unbind a delegate.)
		PC->OnPlayerPickupItem.AddDynamic(this, &UInventoryUserWidget::CallPlayerPickupItem); // Bind the delegate from the PC that calls the BlueprintImplementableEvent.
	}
}

Hope this was helpful i spent some time on the crash i got when not checking for IsLocalPlayerController().
And tought it might be a nice share for anyone else having the issue.

2 Likes

Thanks for this.
I think for people that are not familiar with Delegate & BlueprintImplementableEvent, you may just update your sample for the delegate part with the .H delegate & BlueprintImplementableEvent declaration so people understand how to setup this.

You can also put the RPC function to demonstrate how you called the delegate.

in all case, it’s clearly an useful information.

Hi! .

Thanks for yours tutorial.
I did your tutorial, but i can’t see widget
****because InventoryUIClass is null pointer value.

When does InventoryUIClass set by pointer value?

What’s wrong?

I think that widget blueprint not executed.

How can i call widget blueprint?

  1. Myproject name is widgettest2.

<widgettest2.h>


#ifndef __WIDGETTEST2_H__
#define __WIDGETTEST2_H__

#include "EngineMinimal.h"

//UMG
#include "Runtime/UMG/Public/UMG.h"
#include "Runtime/UMG/Public/UMGStyle.h"
#include "Runtime/UMG/Public/Slate/SObjectWidget.h"
#include "Runtime/UMG/Public/IUMGModule.h"
#include "Runtime/UMG/Public/Blueprint/UserWidget.h"
//

#endif


<UInventoryWidget.h>


// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "Blueprint/UserWidget.h"
#include "UInventoryWidget.generated.h"

/**
 * 
 */
UCLASS()
class WIDGETTEST2_API UUInventoryWidget : public UUserWidget
{
	GENERATED_BODY()
	

	
	
};

<UInventoryWidget.cpp>


// Fill out your copyright notice in the Description page of Project Settings.

#include "widgettest2.h"
#include "UInventoryWidget.h"

<MyPlayerController.h>


// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "GameFramework/PlayerController.h"
#include "MyPlayerController.generated.h"

/**
 * 
 */
UCLASS()
class WIDGETTEST2_API AMyPlayerController : public APlayerController
{
	GENERATED_BODY()

public:
	virtual void BeginPlay() override;


public:
		// The class that will be used for the players Inventory UI
		UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Player, HUD and UI")
		TSubclassOf<class UUInventoryWidget> InventoryUIClass;

	// The instance of the players Inventory UI Widget
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Player, HUD and UI")
	class UUInventoryWidget* InventoryWidget;

	
	
};

<MyPlayerController.cpp>


// Fill out your copyright notice in the Description page of Project Settings.

#include "widgettest2.h"
#include "MyPlayerController.h"
#include "UInventoryWidget.h"



void AMyPlayerController::BeginPlay()
{
	Super::BeginPlay();

	// Only create the UI on the local machine (dose not excist on the server.)
	if (IsLocalPlayerController())
	{
		**if (InventoryUIClass) // Check the selected UI class is not NULL**		{
			if (!InventoryWidget) // If the widget is not created and == NULL
			{
				InventoryWidget = CreateWidget<UUInventoryWidget>(this, InventoryUIClass); // Create Widget
				if (!InventoryWidget)
					return;
				InventoryWidget->AddToViewport(); // Add it to the viewport so the Construct() method in the UUserWidget:: is run.
				InventoryWidget->SetVisibility(ESlateVisibility::Hidden); // Set it to hidden so its not open on spawn.
			}
		}
	}
}

<MyWidget - Widget Blueprint>

That’s all!!

Help me, please.

Engine Version : 4.7.0
OS : Windows 7

Hey there,

this is not my tutorial but the “TSubclassOf<class UUInventoryWidget> InventoryUIClass;” should be set in the Blueprint Default Value
of your PlayerController. Go into your “PlayerController” BP and click on “Class Defaults” at the top. Make sure that you assigned
the correct Class to the “InventoryUIClass” variable .

Hey, if you are having issues with intellisense about not being able to open UserWidget.h you should generate visual studio files to fix it.

This looks like an awesome tutorial! Now, I have a question; would it be possible to have the HUD class be responsible for spawning the widgets? My current implementation causes my game to freeze if I put it into the beginplay function. The reason I want to do this is because for certain functions in my widgets, I want access to canvas functions like project or deproject.

Pointless if its not working

Thanks, that worked for me. For anyone who doesn’t know, you generate visual studio files by going to your project folder, right clicking the .uproject file, and clicking “generate visual studio project files”.

Can anyone help me with this? I am getting an error and don’t know what it means:

error C2228: left of ‘.__Internal_RemoveDynamic’ must have class/struct/union
error C2228: left of ‘.__Internal_AddDynamic’ must have class/struct/union


if (PC)
{
	// Calls CallPlayerPickupItem() that in turn calls the "BlueprintImplementableEvent" on OnPlayerPickedItem()
        PC->UI_UpdateScore.RemoveDynamic(this, &USHud::CallUpdateScore); // Remove the delegate before binding it. (Its always safe to unbind a delegate.)
	PC->UI_UpdateScore.AddDynamic(this, &USHud::CallUpdateScore); // Bind the delegate from the PC that calls the BlueprintImplementableEvent.
}

Thanks for this man this helped me perfectly.

Freeze like lock up, or just pause for a moment while it creates it?

It should work fine from any class (i have done it from gameinstance, playercontroller, and a gamemode for various things)

If it is doing it when it creates it, the best way around this is to create the widget on begin play, and hide it, then unhide it when you wish to show it. this is what im doing from player controller and i do not get a pause.)

My hud is actually a blueprint based off my c++ hud class, that attaches a widget in there.
Something like that might do what you want. :slight_smile:

Just in case those who face InventoryUIClass is being NULL like above replies and myself, there is a solution thx to .

Instead of TSubclassOf, use TAssetSubclassOf with LoadSynchronous();

is new code



UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Player, HUD and UI")
	TAssetSubclassOf<class UInventoryUserWidget> InventoryUIClass;

	// The instance of the players Inventory UI Widget
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Player, HUD and UI")
	class UInventoryUserWidget* InventoryWidget;




void AMyPlayerController::BeginPlay()
{
	Super::BeginPlay();

	// Only create the UI on the local machine (dose not excist on the server.)
	if (IsLocalPlayerController())
	{
		
		if (!InventoryWidget) // If the widget is not created and == NULL
		{
			InventoryWidget = CreateWidget<UInventoryUserWidget>(this, InventoryUIClass.LoadSynchronous()); // Create Widget
			if (!InventoryWidget )
			    return;
			InventoryWidget->AddToViewport(); // Add it to the viewport so the Construct() method in the UUserWidget:: is run.
			InventoryWidget->SetVisibility(ESlateVisibility::Hidden); // Set it to hidden so its not open on spawn.
		}
		
	}
}


after that, make sure your GameMode has BP version of your controller class. Yes, you need your own GameModeBP with BP version of your controller class.

this is the thread how I got to know the solution.

Thanks my brudda for posting this :slight_smile: