Slate, Hello

Rate this Article:
4.33
(6 votes)

Approved for Versions:4.8

Note
Some or all of the information on this page is inconsistent, irrelevant or confusing.

Please help clean it up if you are able.

Hello Slate!

This tutorial assumes an intermediate understanding of C++ and event driven systems. It will give you a basic introduction to adding HUD capable of rendering Slate Widgets. In line with ancient tradition, the Slate Widget will render a text-box displaying the message "Hello, Slate!". Aside from the sources, there are a several steps involved in setting up a project that can handle Slate Widgets. Some things that may be glaringly obvious to someone with experience might be glazed over that aren't as obvious to someone just learning C. If you're having trouble, there is a start-to-finish video walk-through.

Update 4.8 (Katianie 6/14/2015): I am modifying this tutorial to reflect the changes in Unreal 4.8. I followed this tutorial a few hours ago and I noticed that about half the stuff that was mentioned has been changed.

Creating a project

If you have not done so already the first thing to do is to create a blank C++ project. For the purpose of this tutorial, it is recommended that you have "Include Starter Content" unticked. This tutorial will use the project name HelloSlate, however you can call it anything of your own choosing as long as you're comfortable with making the appropriate changes to the provided source files. For beginners I would suggest that you do not diverge from the provided example.

You can do the above or you can manually create the the four files that we will need:

  • StandardHUD.h
  • StandardHUD.cpp
  • StandardSlateWidget.h
  • StandardSlateWidget.cpp

Allow C++ Access to Slate API by Modifying Build File

Open the HelloSlate.Build.cs file (typically located in $Projectfolder/$Projectname/Source/$Projectname) and modify it to allow Slate:

// Fill out your copyright notice in the Description page of Project Settings.
using UnrealBuildTool;
 
public class HelloSlate : ModuleRules
{
	public HelloSlate(TargetInfo Target)
	{
		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
 
		PrivateDependencyModuleNames.AddRange(new string[] {  });
 
		// Uncomment if you are using Slate UI
		PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
 
		// Uncomment if you are using online features
		// PrivateDependencyModuleNames.Add("OnlineSubsystem");
		// if ((Target.Platform == UnrealTargetPlatform.Win32) || (Target.Platform == UnrealTargetPlatform.Win64))
		// {
		//		if (UEBuildConfiguration.bCompileSteamOSS == true)
		//		{
		//			DynamicallyLoadedModuleNames.Add("OnlineSubsystemSteam");
		//		}
		// }
	}
}

Save and close, next time you build your project your sources can link to the Slate API.

Creating a new Slate Widget class

All together this project spans 4 source files. These files should now be created but are blank. Below Is the code behind each file. The StandardHUD class is basically just copy paste a default HUD. The Widget files ("What the hell's a Widget!?" -Rodney Dangerfield) aka The Slate Widget is a custom Slate GUI component. The widget is where we will display "Hello Slate!".

The four source files are:

  • StandardHUD.h
  • StandardHUD.cpp
  • StandardSlateWidget.h
  • StandardSlateWidget.cpp

As you might be aware of already, when you create .cpp and .h files manually, Unreal puts the files in the intermediate folder. Make sure your files are in the source folder like they should be.

StandardHUD.h:

// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "GameFramework/HUD.h"
#include "StandardHUD.generated.h"
 
class SStandardSlateWidget;
 
UCLASS()
class AStandardHUD : public AHUD
{
	GENERATED_BODY()
public:
	AStandardHUD();
 
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/////Reference to an SCompoundWidget, TSharedPtr adds to the refcount of MyUIWidget
	/////MyUIWidget will not self-destruct as long as refcount > 0
	/////MyUIWidget refcount will be (refcout-1) if HUD is destroyed.
	TSharedPtr<SStandardSlateWidget> MyUIWidget;
 
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/////Called as soon as game starts, create SCompoundWidget and give Viewport access
	void BeginPlay();
};

StandardHUD.cpp:

// Fill out your copyright notice in the Description page of Project Settings.
 
#include "HelloSlate.h"
#include "StandardSlateWidget.h"
#include "StandardHUD.h"
 
AStandardHUD::AStandardHUD()
{
 
}
 
void AStandardHUD::BeginPlay()
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/////So far only TSharedPtr<SMyUIWidget> has been created, now create the actual object.
	/////Create a SMyUIWidget on heap, our MyUIWidget shared pointer provides handle to object
	/////Widget will not self-destruct unless the HUD's SharedPtr (and all other SharedPtrs) destruct first.
	MyUIWidget = SNew(SStandardSlateWidget).OwnerHUD(this);
 
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/////Pass our viewport a weak ptr to our widget
	/////Viewport's weak ptr will not give Viewport ownership of Widget
	GEngine->GameViewport->AddViewportWidgetContent(SNew(SWeakWidget).PossiblyNullContent(MyUIWidget.ToSharedRef()));
 
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/////Set widget's properties as visible (sets child widget's properties recursively)
	MyUIWidget->SetVisibility(EVisibility::Visible);
}


StandardSlateWidget.h:

//Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
 
#pragma once
#include "StandardHUD.h"
#include "SlateBasics.h"
 
class SStandardSlateWidget : public SCompoundWidget
{
	SLATE_BEGIN_ARGS(SStandardSlateWidget){}
 
	/*See private declaration of OwnerHUD below.*/
	SLATE_ARGUMENT(TWeakObjectPtr<class AStandardHUD>, OwnerHUD)
 
	SLATE_END_ARGS()
 
public:
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/////Needed for every widget
	/////Builds this widget and any of it's children
	void Construct(const FArguments& InArgs);
 
private:
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/////Pointer to our parent HUD
	/////To make sure HUD's lifetime is controlled elsewhere, use "weak" ptr.
	/////HUD has "strong" pointer to Widget,
	/////circular ownership would prevent/break self-destruction of hud/widget (cause memory leak).
	TWeakObjectPtr<class AStandardHUD> OwnerHUD;
};

StandardSlateWidget.cpp:

#include "HelloSlate.h"
#include "StandardSlateWidget.h"
#include "StandardHUD.h"
 
#define LOCTEXT_NAMESPACE "SStandardSlateWidget"
 
void SStandardSlateWidget::Construct(const FArguments& InArgs)
{
	OwnerHUD = InArgs._OwnerHUD;
 
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/////If the code below doesn't look like C++ to you it's because it (sort-of) isn't,
	/////Slate makes extensive use of the C++ Prerocessor(macros) and operator overloading,
	/////Epic is trying to make our lives easier, look-up the macro/operator definitions to see why.
	ChildSlot
	.VAlign(VAlign_Fill)
	.HAlign(HAlign_Fill)
	[
		SNew(SOverlay)
		+SOverlay::Slot()
		.VAlign(VAlign_Top)
		.HAlign(HAlign_Center)
		[
			SNew(STextBlock)
			.ShadowColorAndOpacity(FLinearColor::Black)
			.ColorAndOpacity(FLinearColor::Red)
			.ShadowOffset(FIntPoint(-1, 1))
                        .Font(FSlateFontInfo("Veranda", 16))
			.Text(LOCTEXT("HelloSlate", "Hello, Slate!"))
		]
	];
}
 
#undef LOCTEXT_NAMESPACE


Now, clean/rebuild your project, launch the Editor from Visual Studio. The last thing we need to do is set our GameMode's HUD class to the one we just built. Every project has a default Game Mode, and every GameMode has a default Pawn, HUD, PlayerController, and GameState. To do this in 4.8, we will modify the HelloSlateGameMode.h and cpp. This is a necessary step to tell Unreal what HUD to use by default:

HelloSlateGameMode.h:

// Fill out your copyright notice in the Description page of Project Settings.
 
#pragma once
#include "GameFramework/GameMode.h"
#include "HelloSlateGameMode.generated.h"
 
UCLASS()
class AHelloSlateGameMode : public AGameMode
{
	GENERATED_BODY()
 
public:
	AHelloSlateGameMode();
};

HelloSlateGameMode.cpp:

// Fill out your copyright notice in the Description page of Project Settings.
 
#include "HelloSlate.h"
#include "StandardHUD.h"
#include "HelloSlateGameMode.h"
 
AHelloSlateGameMode::AHelloSlateGameMode() : Super()
{
	//Set the hud class to use our custom HUD by default.
	this->HUDClass = AStandardHUD::StaticClass();
}

Hit "play", hopefully you CAN see the result at the top of the Viewport. If you run into any questions try dropping a line in this wiki's thread.

https://forums.unrealengine.com/showthread.php?822-Slate-Tutorial

For more information on more advanced uses of Slate you can see some examples of Loading Slate Styles & Resources here...
https://wiki.unrealengine.com/Loading_Slate_Styles_%26_Resources

Update 4.8: Thank you Unreal community for having the old tutorial here so I had a place to start. I will try to go through the further reading and also update those as well.

Update 4.8.2 (7/18/2015): I probably should have done this sooner but here is a link to the full project. I started to mess around a bit with the stuff in the next tutorial "How to Make Fancy Custom Buttons" so there is some commented out code related to that. I just tested the project before zipping it up and it works, let me know if you guys have any trouble, you can reach me on Skype at Katianie9 or send me a message through here.


Further Reading

Slate,_How_to_Make_Fancy_Custom_SButtons