Announcement

Collapse
No announcement yet.

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

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    [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.
    Code:
    	// 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.
    Code:
    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.
    Code:
    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!
    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)

    Here is a example of this.
    Code:
    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.

    WCode
    Last edited by WCode; 11-25-2014, 11:46 AM.

    #2
    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.

    Comment


      #3
      Hi! WCode.

      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>

      Code:
      #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>

      Code:
      // 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>


      Code:
      // Fill out your copyright notice in the Description page of Project Settings.
      
      #include "widgettest2.h"
      #include "UInventoryWidget.h"

      <MyPlayerController.h>

      Code:
      // 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>

      Code:
      // 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>
      Click image for larger version

Name:	MyWidget1.PNG
Views:	1
Size:	160.8 KB
ID:	1071442

      Click image for larger version

Name:	MyWidget2.PNG
Views:	1
Size:	136.0 KB
ID:	1071443

      That's all!!

      Help me, please.

      Engine Version : 4.7.0
      OS : Windows 7
      Last edited by eXi; 03-29-2015, 06:16 AM. Reason: Added Code Tag

      Comment


        #4
        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 here.
        Open for contracted work | C++/BP (incl. Multiplayer) | Tutoring | VR

        My UE4 Blog/Page with Tutorials and more: Hit me for ALL the things!
        (Including 100+ Pages Multiplayer Network Compendium to get you started.)

        Comment


          #5
          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.

          Comment


            #6
            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.

            Comment


              #7
              Pointless if its not working

              Comment


                #8
                Originally posted by Raikoh View Post
                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.
                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".

                Comment


                  #9
                  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

                  Code:
                  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.
                  }

                  Comment


                    #10
                    Thanks for this man this helped me perfectly.
                    Outer Planet Studios
                    http://outerplanet.webflow.io/

                    Comment


                      #11
                      Originally posted by cridia View Post
                      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.
                      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.
                      Outer Planet Studios
                      http://outerplanet.webflow.io/

                      Comment


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

                        Instead of TSubclassOf, use TAssetSubclassOf with LoadSynchronous();

                        here is new code

                        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;
                        Code:
                        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.

                        https://forums.unrealengine.com/show...ausing-trouble

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

                        Comment


                          #13
                          Thanks my brudda for posting this

                          Comment

                          Working...
                          X