跳轉至

UE 擴展編輯器菜單

記錄 UE 如何擴展編輯器選單

Hook

Hook 可以理解為擴展選單的錨點,我們可以在 Hook 的前面或後面設置新添加的選單命令,UE 自帶的編輯器選單命令基本都帶有 Hook,UE5 下打開 編輯 - 編輯器偏好設置 - 通用 - 其他 - 顯示 UI 擴展點 來顯示所有選單的 Hook:

模組依賴

請在專案的.Build.cs檔案裡加入依賴的模組 LevelEditor、Slate、SlateCore、EditorStyle、EditorWidgets、UnrealEd、ToolMenus:

PrivateDependencyModuleNames.AddRange(
    new string[]
    {
        "Core",
        "Engine",
        "CoreUObject",
        "LevelEditor",
        "Slate",
        "SlateCore",
        "EditorStyle",
        "EditorWidgets",
        "UnrealEd",
        "ToolMenus",
    }
    );

添加菜單欄

直接上程式碼

auto MenuExtender = MakeShared<FExtender>();

MenuExtender->AddMenuBarExtension(
    "Help", EExtensionHook::After,      // Create After Help
    nullptr,
    FMenuBarExtensionDelegate::CreateLambda([](FMenuBarBuilder& MenuBarBuilder)
    {
        MenuBarBuilder.AddPullDownMenu(
            TEXT("MenuTest"),       // Name
            TEXT("MenuTest"),       // Tips
            FNewMenuDelegate::CreateLambda([](FMenuBuilder& MenuBuilder)
            {
                // create sub menus
            }),
            TEXT("MenuText"));      // New Hook
    })
);
FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor").GetMenuExtensibilityManager()->AddExtender(MenuExtender);

執行以上代碼可以看到在 幫助 後面加上了一個菜單欄 MenuTest:

新增指令

使用 MenuBuilder.AddMenuEntry 接口:

// Inside MenuTest Lambda
MenuBuilder.AddMenuEntry(
    FText::FromName("MenuTestAction"), FText::FromName("MenuTestAction"),
    FSlateIcon(), FUIAction(FExecuteAction::CreateLambda([]()
    {
        // do action
    })));

將上述程式碼放入 CreateLambda 中,即可生成選單命令:

菜單分節

使用 MenuBuilder.BeginSectionMenuBuilder.EndSection

MenuBuilder.BeginSection(NAME_None, FText::FromName("MenuTestSection"));
// code to create action
MenuBuilder.EndSection();

分隔符

MenuBuilder.AddMenuSeparator();

子選單

子選單類似於選單列,需在 Lambda 內定義:

MenuBuilder.AddSubMenu(
    FText::FromName("MenuTestSub"), 
    FText::FromName("MenuTestSub"), 
    FNewMenuDelegate::CreateLambda([](FMenuBuilder& MenuBuilder)
    {
        MenuBuilder.AddMenuEntry(
            FText::FromName("MenuTestSubAction"), FText::FromName("MenuTestSubAction"),
            FSlateIcon(), FUIAction(FExecuteAction::CreateLambda([]()
            {
                // do action
            })));
    }));

SlateUI 控件

還可以添加 UI 控件:

MenuBuilder.AddWidget(
    SNew(SHorizontalBox)
        + SHorizontalBox::Slot()
        .AutoWidth()
        [
            SNew(SEditableTextBox)
            .MinDesiredWidth(50)
            .Text(FText::FromName("MenuTestWidget"))
        ]

        + SHorizontalBox::Slot()
        .AutoWidth()
        .Padding(5, 0, 0, 0)
        [
        SNew(SButton)
        .Text(FText::FromName("ExtendWidget"))
        .OnClicked(FOnClicked::CreateLambda([]()
        {
            // do action
            return FReply::Handled();
        }))
        ],
    FText::GetEmpty()
);

這裡不會詳細展開有關 Slate UI 的內容,如果有興趣的話,可以去尋找其他文章觀看。

增加 Hook 選單

譬如在 工具 - 編程 裡面增加一個命令:

MenuExtender->AddMenuExtension(
    "Programming", EExtensionHook::After,
    nullptr,
    FMenuExtensionDelegate::CreateLambda([](FMenuBuilder& MenuBuilder)
    {
        MenuBuilder.AddMenuEntry(
        FText::FromName("MenuTestAction"), FText::FromName("MenuTestAction"),
        FSlateIcon(), FUIAction(FExecuteAction::CreateLambda([]()
        {
            // do action
        })));
    })
);

同樣的道理,您可以新增其他種類的菜單。

完整代碼

void BuildTestMenu()
{
    auto MenuExtender = MakeShared<FExtender>();

    MenuExtender->AddMenuBarExtension(
        "Help", EExtensionHook::After,
        nullptr,
        FMenuBarExtensionDelegate::CreateLambda([](FMenuBarBuilder& MenuBarBuilder)
        {
            MenuBarBuilder.AddPullDownMenu(
                FText::FromName("MenuTest"),
                FText::FromName("MenuTest"),
                FNewMenuDelegate::CreateLambda([](FMenuBuilder& MenuBuilder)
                {
                    MenuBuilder.BeginSection(NAME_None, FText::FromName("MenuTestSection"));
                    MenuBuilder.AddMenuSeparator();
                    MenuBuilder.AddMenuEntry(
                        FText::FromName("MenuTestAction"), FText::FromName("MenuTestAction"),
                        FSlateIcon(), FUIAction(FExecuteAction::CreateLambda([]()
                        {
                            // do action
                        })));

                    MenuBuilder.AddSubMenu(
                        FText::FromName("MenuTestSubb"),
                        FText::FromName("MenuTestSubb"),
                        FNewMenuDelegate::CreateLambda([](FMenuBuilder& MenuBuilder)
                        {
                            MenuBuilder.AddMenuEntry(
                                FText::FromName("MenuTestSubAction"), FText::FromName("MenuTestSubAction"),
                                FSlateIcon(), FUIAction(FExecuteAction::CreateLambda([]()
                                {
                                    // do action
                                })));
                        }));
                    MenuBuilder.EndSection();

                    MenuBuilder.AddWidget(
                    SNew(SHorizontalBox)
                         + SHorizontalBox::Slot()
                         .AutoWidth()
                         [
                             SNew(SEditableTextBox)
                             .MinDesiredWidth(50)
                             .Text(FText::FromName("MenuTestWidget"))
                         ]
                         + SHorizontalBox::Slot()
                         .AutoWidth()
                         .Padding(5, 0, 0, 0)
                         [
                            SNew(SButton)
                            .Text(FText::FromName("ExtendWidget"))
                            .OnClicked(FOnClicked::CreateLambda([]()
                            {
                                // do action
                                return FReply::Handled();
                            }))
                         ],
                     FText::GetEmpty()
                    );
                }),
                "MenuTest");
        })
    );

    MenuExtender->AddMenuExtension(
        "Programming", EExtensionHook::After,
        nullptr,
        FMenuExtensionDelegate::CreateLambda([](FMenuBuilder& MenuBuilder)
        {
            MenuBuilder.AddMenuEntry(
            FText::FromName("MenuTestAction"), FText::FromName("MenuTestAction"),
            FSlateIcon(), FUIAction(FExecuteAction::CreateLambda([]()
            {
                // do action
            })));
        })
    );

    FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor").GetMenuExtensibilityManager()->AddExtender(MenuExtender);
}

Original: https://wiki.disenone.site/tc

This post is protected by CC BY-NC-SA 4.0 agreement, should be reproduced with attribution.

此訊息是使用 ChatGPT 翻譯的,若有反饋請指出任何遺漏之處。