Editor Utility Widgets are one of the new feature of the Unreal Engine since 4.22. It allows users to define editor widgets using the UMG designer. We already covered this topic previously, so if you want to start with Editor Utility Widgets, you may want to check this article, this one and this one.
In this article, we will answer to a question we can have when using the Editor Utility Widgets: how can we programmatically start an Editor Utility Widget?
If you are wondering how an Editor Utility Widget can start another Editor Utility Widget, this article will explain you how to do it.
In the previous articles, the only way to start the Editor Utility Widget was to perform a right-click on it and select Run Editor Utility Widget. But it’s also possible to start it programmatically using C++ and blueprints.
Starting an Editor Utility Widget from C++
First of all, this is an editor only function, so we will need to create a new editor plugin (everything is explained for this in the previous article about Editor Utility Widgets in C++).
For this plugin, we will require several dependencies, so the following section must be added to the Build.cs:
PrivateDependencyModuleNames.AddRange(
new string[]
{
"CoreUObject",
"Engine",
"Slate",
"SlateCore",
"UnrealEd",
"Blutility",
"UMG",
"UMGEditor"
// ... add private dependencies that you statically link with here ...
}
);
Then, in this plugin, we will create a UBlueprintFunctionLibrary. Actually, it can be any class, but we will only need to create a static function allowing us to start the Editor Utility Widget, so a UBlueprintFunctionLibrary is enough.
The header of this class will give something like this:
#include "CoreMinimal.h"
#include "Editor/Blutility/Classes/EditorUtilityWidget.h"
#include "Runtime/Engine/Classes/Kismet/BlueprintFunctionLibrary.h
#include "EditorWidgetFunctionLibrary.generated.h"
UCLASS(BlueprintType)
class CPPEDITORWIDGET_API UEditorWidgetFunctionLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable)
static void StartWidget(UWidgetBlueprint* Blueprint);
};
The important points to note here are the presence of a StartWidget static function taking as parameter a UWidgetBlueprint object. We may also note the required includes.
The corresponding part in the cpp file with the implementation of the function will be like this:
#include "EditorWidgetFunctionLibrary.h"
#include "Editor/UMGEditor/Public/WidgetBlueprint.h"
#include "Editor/LevelEditor/Public/LevelEditor.h"
#include "Runtime/Core/Public/Modules/ModuleManager.h"
#include "Editor/Blutility/Public/IBlutilityModule.h"
#include "Editor/Blutility/Classes/EditorUtilityWidgetBlueprint.h"
void UEditorWidgetFunctionLibrary::StartWidget(UWidgetBlueprint* Blueprint)
{
if (Blueprint->GeneratedClass->IsChildOf(UEditorUtilityWidget::StaticClass()))
{
const UEditorUtilityWidget* CDO = Blueprint->GeneratedClass->GetDefaultObject();
if (CDO->ShouldAutoRunDefaultAction())
{
// This is an instant-run blueprint, just execute it
UEditorUtilityWidget* Instance = NewObject(GetTransientPackage(), Blueprint->GeneratedClass);
Instance->ExecuteDefaultAction();
}
else
{
FName RegistrationName = FName(*(Blueprint->GetPathName() + TEXT("_ActiveTab")));
FText DisplayName = FText::FromString(Blueprint->GetName());
FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked(TEXT("LevelEditor"));
TSharedPtr LevelEditorTabManager = LevelEditorModule.GetLevelEditorTabManager();
TSharedRef NewDockTab = LevelEditorTabManager->InvokeTab(RegistrationName);
}
}
}
For information, this function is extracted from FAssetTypeActions_EditorUtilityWidgetBlueprint::ExecuteRun(FWeakBlueprintPointerArray InObjects) in AssetTypeActions_EditorUtilityWidgetBlueprint.h.
Once this code copied in the plugin, we have everything required to start an Editor Widget Utility from C++. We just need to call StartWidget with a reference on the UWidgetBlueprint we want to start.
Usage in blueprints
The function previously defined is exposed to blueprints (marked as BlueprintCallable), this means the plugin we created allow us to programmatically start Editor Utility Widgets using blueprints. Indeed, the StartWidget function is callable from other Editor Utility Widgets, so now an Editor Utility Widget can start another widget.
And it’s straightforward:
Here we just created a simple Editor Utility Widget with only one button, and on the click on this button we want to spawn another widget. And, the previous figure shows all we need to do to implement this.
Conclusion
This article presents how we can programmatically start an Editor Utility Widget using either C++ or blueprints (but with the creation of a C++ plugin being mandatory).
And just so you know, this article is actually a request from a reader willing to know how to programmatically start an Editor Widget Blueprint (right now there’s still a lack of documentation and ressources about Editor Utility Widgets). If you’re interrested in more articles about this, or if you want to request an article about a specific topic, you can follow us and contact us on Twitter and Facebook.
Thank you soo much for this Article!!! Helped me a lot!! 🙂
Hey! This is my 1st comment here so I just wanted to give a quick
shout out and say I really enjoy reading your blog posts.
Can you suggest any other blogs/websites/forums that go over the same
subjects? Thanks for your time!
Hey!. this anwser is not complete, you have to manually open your widget once, then it will register the tab with the unreal’s tab spawner.
you will need to register your tab first and the create a widget based on your tab spawner:
here you can update your blog:
if (!LevelEditorTabManager->CanSpawnTab(RegistrationName))
{
//UEditorUtilityWidgetBlueprint* WidgetBlueprint = Cast(Blueprint);
LevelEditorTabManager->RegisterTabSpawner(RegistrationName, FOnSpawnTab::CreateStatic(&UPipelineStatics::SpawnEditorUITab, Blueprint))
.SetDisplayName(DisplayName)
.SetMenuType(ETabSpawnerMenuType::Hidden);
}
and then you will need a function to create your widget inside the SpawnEditorUITab function:
TSharedRef UPipelineStatics::SpawnEditorUITab(const FSpawnTabArgs& SpawnTabArgst, UWidgetBlueprint* Blueprint)
{
TSharedRef SpawnedTab = SNew(SDockTab);
TSubclassOf WidgetClass = Blueprint->GeneratedClass;
UWorld* World = GEditor->GetEditorWorldContext().World();
check(World);
UEditorUtilityWidget* CreatedUMGWidget = CreateWidget(World, WidgetClass);
if (CreatedUMGWidget)
{
TSharedRef CreatedSlateWidget = CreatedUMGWidget->TakeWidget();
SpawnedTab->SetContent(CreatedSlateWidget);
}
return SpawnedTab;
}
this is without modifying any source code. just as a plugin
Perfect!
thank you so much! you really helped me on the most though step!
Great article but the cpp you posted does not work on 4.22 because of some compile errors.
Here’s a fixed version of it.
============================
#include “EditorWidgetFunctionLibrary.h”
#include “Editor/UMGEditor/Public/WidgetBlueprint.h”
#include “Editor/LevelEditor/Public/LevelEditor.h”
#include “Runtime/Core/Public/Modules/ModuleManager.h”
#include “Editor/Blutility/Public/IBlutilityModule.h”
#include “Editor/Blutility/Classes/EditorUtilityWidgetBlueprint.h”
void UTSBBlueprintFunctionLibrary::StartWidget(UWidgetBlueprint* Blueprint)
{
if (Blueprint->GeneratedClass->IsChildOf(UEditorUtilityWidget::StaticClass()))
{
const UEditorUtilityWidget* CDO = Blueprint->GeneratedClass->GetDefaultObject();
if (CDO->ShouldAutoRunDefaultAction())
{
// This is an instant-run blueprint, just execute it
UEditorUtilityWidget* Instance = NewObject(GetTransientPackage(), Blueprint->GeneratedClass);
Instance->ExecuteDefaultAction();
}
else
{
FName RegistrationName = FName(*(Blueprint->GetPathName() + TEXT(“_ActiveTab”)));
FText DisplayName = FText::FromString(Blueprint->GetName());
FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked(TEXT(“LevelEditor”));
TSharedPtr LevelEditorTabManager = LevelEditorModule.GetLevelEditorTabManager();
TSharedRef NewDockTab = LevelEditorTabManager->InvokeTab(RegistrationName);
}
}
}
Hi First time comment, When I write this line:
const UeditorUtilityWidget* CDO = Blueprint->GeneratedClass->GetDefaultObject();
I get an error saying the a value of type UObject* cannot be used to initialize an entity of type const UEditorUtilityWidget*, shouldnt this be casted to the appropriate type?
Thank you
Also, New Object is a template class thus requires that you define the type, like this:
UEditorUtilityWidget* inst = NewObject(GetTransientPackage(), a_Blueprint->GeneratedClass);
Else I get an error.
I meant template function**
As of 4.23 they also made this possible without C++, you can auto-start a widget via ini file – see this thread: https://forums.unrealengine.com/development-discussion/blueprint-visual-scripting/1661977-4-23-how-to-auto-start-editor-utility-widgets-new-feature
Thank you so much for this article. I was diving in the source code to do exactly this without any luck, but your article saved me!
inside your function,
auto EditorUIClass = LoadClass(nullptr, TEXT(“path to your widget_C”));
UWorld* World = GEditor->GetEditorWorldContext().World();
check(World);
UEditorUtilityWidget* CreatedUMGWidget = CreateWidget(World, EditorUIClass);
FVector2D Size = (400, 600); // set a window size to your widget
auto MyWindow = SNew(SWindow).ClientSize(Size).MaxHeight(600).MaxWidth(400);
MyWindow->SetContent(CreatedUMGWidget->TakeWidget());
FSlateApplication::Get().AddWindow(MyWindow, true);