跳轉至

UE 使用路徑形式擴展選單

記錄如何在UE中實現路徑形式擴展菜單

如果對於UE擴展選單不太熟悉的話,建議先簡單看一下:UE擴展編輯器選單

This text should be translated into Traditional Chinese as:

本文內容是基於插件:UE.EditorPlus

節點管理

將菜單結構化,可依據樹狀結構管理,父節點可以包含子節點:

class EDITORPLUS_API FEditorPlusMenuBase: public TSharedFromThis<FEditorPlusMenuBase>
{
protected:
    // sub menus
    TArray<TSharedRef<FEditorPlusMenuBase>> Children;
}

同時建立父節點和子節點:

void FEditorPlusMenuBase::Register(FMenuBuilder& MenuBuilder)
{
    for (const auto Menu: Children)
    {
        Menu->Register(MenuBuilder);
    }
}

當然每個節點的具體建立行為會有些不同,覆寫虛擬函數來實現:

// Menubar
void FEditorPlusMenuBar::Register(FMenuBarBuilder& MenuBarBuilder)
{
    MenuBarBuilder.AddPullDownMenu(
        GetFriendlyName(),
        GetFriendlyTips(),
        // Delegate to call Register
        FEditorPlusMenuManager::GetDelegate<FNewMenuDelegate>(GetUniqueId()),       
        Hook);
}

// Section
void FEditorPlusSection::Register(FMenuBuilder& MenuBuilder)
{
    MenuBuilder.BeginSection(Hook, GetFriendlyName());
    FEditorPlusMenuBase::Register(MenuBuilder);
    MenuBuilder.EndSection();
}

// Separator
void FEditorPlusSeparator::Register(FMenuBuilder& MenuBuilder)
{
    MenuBuilder.AddMenuSeparator(Hook);
    FEditorPlusMenuBase::Register(MenuBuilder);
}

// SubMenu
void FEditorPlusSubMenu::Register(FMenuBuilder& MenuBuilder)
{
    MenuBuilder.AddSubMenu(
        GetFriendlyName(),
        GetFriendlyTips(),
        FNewMenuDelegate::CreateSP(this, &FEditorPlusSubMenu::MakeSubMenu),
        false,
        FSlateIcon(),
        true,
        Hook
    );
}

// Command
void FEditorPlusCommand::Register(FMenuBuilder& MenuBuilder)
{
    MenuBuilder.AddMenuEntry(
        CommandInfo->Label, CommandInfo->Tips, CommandInfo->Icon,
        CommandInfo->ExecuteAction, CommandInfo->Hook, CommandInfo->Type);
}

// ......

通過路徑生成節點

根據樹狀結構組織菜單,路徑格式就可以定義一條菜單的樹狀結構:

"/<Hook>Help/<MenuBar>BarTest/<SubMenu>SubTest/<Command>Action"

以上路徑即可定義一系列選單的建立:

  • <Hook>Help:位置在 Hook 名稱為 Help 的選單後
  • <MenuBar>BarTest:建立一個類型為 MenuBar 的選單,名稱為 BarTest
  • <SubMenu>SubTest:建立子節點,類型為 SubMenu,名稱為 SubTest <Command>Action:最後創建一個命令

接口调用形式可以很简洁:

const FString Path = "/<Hook>Help/<MenuBar>BarTest/<SubMenu>SubTest/<Command>Action";
FEditorPlusPath::RegisterPathAction(
    Path, 
    FExecuteAction::CreateLambda([]
    {
        // do action
    })
);

自訂格式生成節點

我們仍然保留了笨重的方式來建立選單,這種方式能夠允許更詳細的設置,程式碼的組織形式與 UE 的 SlateUI 寫法有些相似:

EP_NEW_MENU(FEditorPlusMenuBar)("BarTest")
->RegisterPath()
->Content({
    EP_NEW_MENU(FEditorPlusSubMenu)("SubTest")
    ->Content({
        EP_NEW_MENU(FEditorPlusCommand)("Action")
        ->BindAction(FExecuteAction::CreateLambda([]
            {
                // do action
            })),
    })
});

混合形式

當然,本身路徑形式和自定義生成的選單,都是相同的,它們之間可以混用,有很大的靈活性:

FEditorPlusPath::RegisterPath(
    "/<MenuBar>BarTest/<SubMenu>SubMenu/<Command>Action1", 
    EP_NEW_MENU(FEditorPlusCommand)("Action1")
    ->BindAction(FExecuteAction::CreateLambda([]
        {
            // do action
        })),
);

FEditorPlusPath::RegisterPath(
    "/<MenuBar>BarTest/<SubMenu>SubMenu/<Command>Action2", 
    EP_NEW_MENU(FEditorPlusCommand)("Action2")
    ->BindAction(FExecuteAction::CreateLambda([]
        {
            // do action
        })),
);

不同地方定義的選單將合併到同一個樹狀結構中,具有相同名稱的節點將被視為同一個節點。換句話說,路徑是唯一的,同一條路徑可以唯一確定一個選單節點。 然後我們也可以找出節點,重新做一些設置和修改:

// set Name and Tips
FEditorPlusPath::GetNodeByPath("/<MenuBar>BarTest")->SetFriendlyName(LOCTEXT("MenuTest", "MenuTest"))->SetFriendlyTips(LOCTEXT("MenuTestTips", "MenuTestTips"));

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

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

此篇文章是使用 ChatGPT 翻譯的,請在反饋指出任何遺漏之處。