How to open an Editor Widget Utility tab from code (python or C++)?

Hello!

I have created an UMG editor widget utility blueprint and would like to open it at some point from my plugin C++ code. How can I achieve that?

I took a look into how in Blutility such an editor widget utility is run when you right click it and select “Run Editor utility Widget” in AssetTypeActions_EditorUtilityWidgetBlueprint.cpp". Unfortunately, this module does not export any of its symbols so I can’t link against it… Here was my attempt (inspired from FAssetTypeActions_EditorUtilityWidgetBlueprint::ExecuteRun):


    void ULogListWidgetBase::OpenEditorUtilityWidgetWindow(UWidgetBlueprint* Blueprint)
    {
        if (Blueprint->GeneratedClass->IsChildOf(UEditorUtilityWidget::StaticClass()))
        {
            const UEditorUtilityWidget* CDO = Blueprint->GeneratedClass->GetDefaultObject<UEditorUtilityWidget>();
            if (CDO->ShouldAutoRunDefaultAction())
            {
                // This is an instant-run blueprint, just execute it
                UEditorUtilityWidget* Instance = NewObject<UEditorUtilityWidget>(GetTransientPackage(), Blueprint->GeneratedClass);
                Instance->ExecuteDefaultAction();
            }
            else
            {
                FName RegistrationName = FName(*(Blueprint->GetPathName() + LOCTEXT("ActiveTabSuffix", "_ActiveTab").ToString()));
                FText DisplayName = FText::FromString(Blueprint->GetName());
                FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>(TEXT("LevelEditor"));
                TSharedPtr<FTabManager> LevelEditorTabManager = LevelEditorModule.GetLevelEditorTabManager();
                if (!LevelEditorTabManager->CanSpawnTab(RegistrationName))
                {
                    IBlutilityModule* BlutilityModule = FModuleManager::GetModulePtr<IBlutilityModule>("Blutility");
                    UEditorUtilityWidgetBlueprint* WidgetBlueprint = Cast<UEditorUtilityWidgetBlueprint>(Blueprint);
                    WidgetBlueprint->SetRegistrationName(RegistrationName);
                    LevelEditorTabManager->RegisterTabSpawner(RegistrationName, FOnSpawnTab::CreateUObject(WidgetBlueprint, &UEditorUtilityWidgetBlueprint::SpawnEditorUITab))
                        .SetDisplayName(DisplayName)
                        .SetGroup(BlutilityModule->GetMenuGroup().ToSharedRef());
                    BlutilityModule->AddLoadedScriptUI(WidgetBlueprint);
                }
                TSharedRef<SDockTab> NewDockTab = LevelEditorTabManager->InvokeTab(RegistrationName);
            }
        }
    }

As I said, I can write this but even when I add Blutility to my list of dependencies, I get the following link errors:


    error LNK2019: unresolved external symbol "private: static class UClass * __cdecl UEditorUtilityWidgetBlueprint::GetPrivateStaticClass(void)" (?GetPrivateStaticClass@UEditorUtilityWidgetBlueprint@@CAPEAVUClass@@XZ) referenced in function "public: static void __cdecl ULogListWidgetBase::OpenEditorUtilityWidgetWindow(class UWidgetBlueprint *)" (?OpenEditorUtilityWidgetWindow@ULogListWidgetBase@@SAXPEAVUWidgetBlueprint@@@Z)

    error LNK2019: unresolved external symbol "public: class TSharedRef<class SDockTab,0> __cdecl UEditorUtilityWidgetBlueprint::SpawnEditorUITab(class FSpawnTabArgs const &)" (?SpawnEditorUITab@UEditorUtilityWidgetBlueprint@@QEAA?AV?$TSharedRef@VSDockTab@@$0A@@@AEBVFSpawnTabArgs@@@Z) referenced in function "public: static void __cdecl ULogListWidgetBase::OpenEditorUtilityWidgetWindow(class UWidgetBlueprint *)" (?OpenEditorUtilityWidgetWindow@ULogListWidgetBase@@SAXPEAVUWidgetBlueprint@@@Z)

Is it something impossible to do at the moment, opening the window of a custom editor widget utility? I must have missed something :slight_smile:

1 Like

Hi! If its still actual question for you, I have found solution, here is my code

#include "Templates/SharedPointer.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"
#include "Framework/Docking/TabManager.h"

TSharedRef<SDockTab> SpawnEditorUITab(const FSpawnTabArgs& SpawnTabArgst, UWidgetBlueprint* Blueprint) {
    TSharedRef<SDockTab> SpawnedTab = SNew(SDockTab);
    TSubclassOf<UEditorUtilityWidget> WidgetClass = Blueprint->GeneratedClass;
    UWorld* World = GEditor->GetEditorWorldContext().World(); 
    check(World);
    UEditorUtilityWidget* CreatedUMGWidget = CreateWidget<UEditorUtilityWidget>(World, WidgetClass);
    if (CreatedUMGWidget)
    {
        TSharedRef<SWidget> CreatedSlateWidget = CreatedUMGWidget->TakeWidget();
        SpawnedTab->SetContent(CreatedSlateWidget);
    }

    return SpawnedTab;
}

void UEditorFunctionLibrary::RunWidget(UWidgetBlueprint* Blueprint)
{
    if (Blueprint->GeneratedClass->IsChildOf(UEditorUtilityWidget::StaticClass()))
    {
        const UEditorUtilityWidget* CDO = Blueprint->GeneratedClass->GetDefaultObject<UEditorUtilityWidget>();
        if (CDO->ShouldAutoRunDefaultAction())
        {
            // This is an instant-run blueprint, just execute it
            UEditorUtilityWidget* Instance = NewObject<UEditorUtilityWidget>(GetTransientPackage(), Blueprint->GeneratedClass);
            Instance->ExecuteDefaultAction();
        }
        else
        {
            FName RegistrationName = FName(*(Blueprint->GetPathName() + TEXT("_ActiveTab")));
            FText DisplayName = FText::FromString(Blueprint->GetName());
            FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>(TEXT("LevelEditor"));
            TSharedPtr<FTabManager> LevelEditorTabManager = LevelEditorModule.GetLevelEditorTabManager();
            if (!LevelEditorTabManager->CanSpawnTab(RegistrationName))
            {
                LevelEditorTabManager->RegisterTabSpawner(RegistrationName, FOnSpawnTab::CreateStatic(&SpawnEditorUITab, Blueprint))
                    .SetDisplayName(DisplayName)
                    .SetMenuType(ETabSpawnerMenuType::Hidden);
            }

            TSharedRef<SDockTab> NewDockTab = LevelEditorTabManager->InvokeTab(RegistrationName);
        }
    }
}

Hi, here’s updated solution for UE5.0.3 : Version: 5.0.3-20979098

  1. In your .build.cs, find PrivateDependencyModuleNames.AddRange
    and add these:

“Blutility”,
“UMG”,
“UMGEditor”,

If “private” dont work, then try public.

  1. Delete VS solution and regenerate from the project .exe

  2. include these:

include “EditorUtilityWidget.h”
include “EditorUtilityWidgetBlueprint.h”
include “EditorUtilitySubsystem.h”

  1. Use this:
	// get the  path of the asset by R.Clicking on the asset and 'Copy Reference'
	const FStringAssetReference widgetAssetPath("/LevelValidationTools/EUW_LevelValidator.EUW_LevelValidator");

	UObject* widgetAssetLoaded = widgetAssetPath.TryLoad();
	if (widgetAssetLoaded == nullptr) {
		UE_LOG(LogTemp, Warning, TEXT("Missing Expected widget class at : /LevelValidationTools/EUW_LevelValidator.EUW_LevelValidator"));
		return;
	}

	UEditorUtilityWidgetBlueprint* widget = Cast<UEditorUtilityWidgetBlueprint>(widgetAssetLoaded);
	if (widget == nullptr) {
		UE_LOG(LogTemp, Warning, TEXT("Couldnt cast /LevelValidationTools/EUW_LevelValidator.EUW_LevelValidator to UEditorUtilityWidgetBlueprint"));
		return;
	}

	UEditorUtilitySubsystem* EditorUtilitySubsystem = GEditor->GetEditorSubsystem<UEditorUtilitySubsystem>();
	EditorUtilitySubsystem->SpawnAndRegisterTab(widget);
1 Like