메뉴와 툴바 확장
FExtender와 UToolMenus를 사용하여 에디터 메뉴와 툴바에 커스텀 버튼 및 메뉴를 추가합니다
UToolMenus 시스템
UE5의 새로운 메뉴 시스템으로 에디터 메뉴를 확장하기
UE5에서는 UToolMenus가 에디터 메뉴 시스템의 표준입니다. 기존 FExtender 방식보다 더 유연하고 안전한 메뉴 등록을 지원합니다.
UToolMenus는 UE 4.24+에서 도입된 새로운 메뉴 시스템으로, 이름 기반 메뉴 등록을 지원합니다. FExtender는 레거시 방식이지만 여전히 일부 에디터 확장점에서 사용됩니다. UE5.5+에서는 가능하면 UToolMenus를 우선 사용하세요.
메뉴 등록 기본 패턴
void FMyGameEditorModule::StartupModule()
{
// ToolMenus가 초기화된 후에 메뉴를 등록
UToolMenus::RegisterStartupCallback(
FSimpleMulticastDelegate::FDelegate::CreateRaw(
this, &FMyGameEditorModule::RegisterMenus));
}
void FMyGameEditorModule::RegisterMenus()
{
// 메인 메뉴바의 "Tools" 메뉴 확장
UToolMenu* Menu = UToolMenus::Get()->ExtendMenu(
"LevelEditor.MainMenu.Tools");
FToolMenuSection& Section = Menu->AddSection(
"MyGameTools",
LOCTEXT("MyGameTools", "My Game Tools"));
Section.AddMenuEntry(
"OpenMyTool",
FToolMenuEntry::InitMenuEntry(
"OpenMyTool",
LOCTEXT("OpenMyTool", "Open My Tool"),
LOCTEXT("OpenMyToolTip", "Opens the custom tool panel"),
FSlateIcon(FAppStyle::GetAppStyleSetName(),
"LevelEditor.GameSettings"),
FUIAction(FExecuteAction::CreateLambda([]()
{
FGlobalTabmanager::Get()->TryInvokeTab(
FName("MyToolTab"));
}))
));
}
주요 메뉴 이름
| 메뉴 이름 | 위치 |
|---|---|
LevelEditor.MainMenu |
메인 메뉴바 전체 |
LevelEditor.MainMenu.File |
파일 메뉴 |
LevelEditor.MainMenu.Edit |
편집 메뉴 |
LevelEditor.MainMenu.Tools |
도구 메뉴 |
LevelEditor.LevelEditorToolBar.PlayToolBar |
플레이 툴바 |
ContentBrowser.AssetContextMenu |
에셋 우클릭 메뉴 |
LevelEditor.ActorContextMenu |
액터 우클릭 메뉴 |
툴바 버튼 추가
레벨 에디터 툴바에 커스텀 버튼 배치하기
void FMyGameEditorModule::RegisterMenus()
{
// 레벨 에디터 툴바 확장
UToolMenu* ToolbarMenu = UToolMenus::Get()->ExtendMenu(
"LevelEditor.LevelEditorToolBar.PlayToolBar");
FToolMenuSection& Section = ToolbarMenu->FindOrAddSection(
"MyToolSection");
// 단일 버튼
Section.AddEntry(
FToolMenuEntry::InitToolBarButton(
"MyToolButton",
FUIAction(FExecuteAction::CreateRaw(
this, &FMyGameEditorModule::OnToolButtonClicked)),
LOCTEXT("ToolBtn", "My Tool"),
LOCTEXT("ToolBtnTip", "Open custom tool"),
FSlateIcon(FAppStyle::GetAppStyleSetName(),
"LevelEditor.GameSettings")
));
// 드롭다운 콤보 버튼
Section.AddEntry(
FToolMenuEntry::InitComboButton(
"MyComboButton",
FUIAction(),
FOnGetContent::CreateRaw(
this, &FMyGameEditorModule::GenerateDropdownMenu),
LOCTEXT("ComboLabel", "Tools"),
LOCTEXT("ComboTip", "Additional tools"),
FSlateIcon(FAppStyle::GetAppStyleSetName(),
"LevelEditor.OpenLevelBlueprint")
));
}
TSharedRef<SWidget> FMyGameEditorModule::GenerateDropdownMenu()
{
FMenuBuilder MenuBuilder(true, nullptr);
MenuBuilder.AddMenuEntry(
LOCTEXT("Action1", "Action 1"),
LOCTEXT("Action1Tip", "First action"),
FSlateIcon(),
FUIAction(FExecuteAction::CreateLambda([]()
{
// Action 1 로직
})));
MenuBuilder.AddMenuEntry(
LOCTEXT("Action2", "Action 2"),
LOCTEXT("Action2Tip", "Second action"),
FSlateIcon(),
FUIAction(FExecuteAction::CreateLambda([]()
{
// Action 2 로직
})));
return MenuBuilder.MakeWidget();
}
UI Commands와 단축키
TCommands로 키보드 단축키를 지원하는 명령 체계 구축
에디터 명령에 키보드 단축키를 바인딩하려면 TCommands 시스템을 사용합니다.
#pragma once
#include "Framework/Commands/Commands.h"
class FMyToolCommands
: public TCommands<FMyToolCommands>
{
public:
FMyToolCommands()
: TCommands<FMyToolCommands>(
TEXT("MyToolCommands"), // 컨텍스트 이름
LOCTEXT("Ctx", "My Tool"), // 표시 이름
NAME_None, // 부모 컨텍스트
FAppStyle::GetAppStyleSetName() // 스타일 셋
)
{}
virtual void RegisterCommands() override;
// 커맨드 정의
TSharedPtr<FUICommandInfo> OpenToolPanel;
TSharedPtr<FUICommandInfo> RunBatchProcess;
TSharedPtr<FUICommandInfo> RefreshAssets;
};
#include "FMyToolCommands.h"
void FMyToolCommands::RegisterCommands()
{
UI_COMMAND(
OpenToolPanel,
"Open Tool Panel",
"Opens the custom tool panel",
EUserInterfaceActionType::Button,
FInputChord(EModifierKey::Control | EModifierKey::Shift,
EKeys::T));
UI_COMMAND(
RunBatchProcess,
"Run Batch Process",
"Runs the batch processing tool",
EUserInterfaceActionType::Button,
FInputChord());
UI_COMMAND(
RefreshAssets,
"Refresh Assets",
"Refreshes all managed assets",
EUserInterfaceActionType::Button,
FInputChord(EModifierKey::Control | EModifierKey::Shift,
EKeys::R));
}
커맨드 바인딩 및 메뉴 연결
void FMyGameEditorModule::StartupModule()
{
// 1. 커맨드 등록
FMyToolCommands::Register();
// 2. 커맨드 리스트 생성 및 매핑
CommandList = MakeShareable(new FUICommandList);
CommandList->MapAction(
FMyToolCommands::Get().OpenToolPanel,
FExecuteAction::CreateRaw(
this, &FMyGameEditorModule::OnOpenToolPanel));
CommandList->MapAction(
FMyToolCommands::Get().RunBatchProcess,
FExecuteAction::CreateRaw(
this, &FMyGameEditorModule::OnRunBatchProcess));
// 3. UToolMenus 메뉴에 커맨드 연결
UToolMenus::RegisterStartupCallback(
FSimpleMulticastDelegate::FDelegate::CreateRaw(
this, &FMyGameEditorModule::RegisterMenus));
}
void FMyGameEditorModule::ShutdownModule()
{
FMyToolCommands::Unregister();
UToolMenus::UnregisterOwner(this);
}
등록된 커맨드는 에디터의 Edit > Editor Preferences > Keyboard Shortcuts에서 사용자가 직접 변경할 수 있습니다. 컨텍스트 이름으로 분류되어 표시됩니다.
FExtender (레거시 방식)
기존 코드베이스와의 호환을 위한 FExtender 패턴
UToolMenus 이전에 사용되던 FExtender 방식입니다. 기존 프로젝트 유지보수나 특정 확장점에서 여전히 필요할 수 있습니다.
TSharedPtr<FExtender> MenuExtender;
void FMyGameEditorModule::StartupModule()
{
MenuExtender = MakeShareable(new FExtender);
// 메뉴바 확장
MenuExtender->AddMenuBarExtension(
"Help", // 기준 메뉴 이름
EExtensionHook::After, // 위치: 뒤에 추가
CommandList, // UI 커맨드 리스트
FMenuBarExtensionDelegate::CreateRaw(
this, &FMyGameEditorModule::AddMenuBarExtension));
// 툴바 확장
MenuExtender->AddToolBarExtension(
"Settings",
EExtensionHook::After,
CommandList,
FToolBarExtensionDelegate::CreateRaw(
this, &FMyGameEditorModule::AddToolBarExtension));
// 레벨 에디터에 Extender 등록
FLevelEditorModule& LevelEditorModule =
FModuleManager::LoadModuleChecked<FLevelEditorModule>(
"LevelEditor");
LevelEditorModule.GetMenuExtensibilityManager()->
AddExtender(MenuExtender);
LevelEditorModule.GetToolBarExtensibilityManager()->
AddExtender(MenuExtender);
}
void FMyGameEditorModule::AddMenuBarExtension(
FMenuBarBuilder& Builder)
{
Builder.AddPullDownMenu(
LOCTEXT("MyMenu", "My Tools"),
LOCTEXT("MyMenuTip", "Custom tool menu"),
FNewMenuDelegate::CreateRaw(
this, &FMyGameEditorModule::FillMyMenu));
}
void FMyGameEditorModule::FillMyMenu(
FMenuBuilder& Builder)
{
Builder.AddMenuEntry(
FMyToolCommands::Get().OpenToolPanel);
Builder.AddMenuSeparator();
Builder.AddMenuEntry(
FMyToolCommands::Get().RunBatchProcess);
}
ShutdownModule()에서 반드시 Extender를 제거해야 합니다- Extension hook 이름은 실제 존재하는 이름이어야 합니다
- 새 프로젝트에서는 UToolMenus를 우선 사용하세요
컨텍스트 메뉴 확장
콘텐츠 브라우저, 뷰포트 우클릭 메뉴에 항목 추가
void FMyGameEditorModule::RegisterMenus()
{
// 에셋 우클릭 메뉴에 항목 추가
UToolMenu* AssetMenu = UToolMenus::Get()->ExtendMenu(
"ContentBrowser.AssetContextMenu");
FToolMenuSection& AssetSection = AssetMenu->FindOrAddSection(
"MyGameAssetActions");
AssetSection.AddMenuEntry(
"ProcessAssets",
FToolMenuEntry::InitMenuEntry(
"ProcessAssets",
LOCTEXT("Process", "Process Selected Assets"),
LOCTEXT("ProcessTip",
"Run custom processing on selected assets"),
FSlateIcon(),
FUIAction(FExecuteAction::CreateLambda([]()
{
// 선택된 에셋 가져오기
TArray<FAssetData> SelectedAssets;
GEditor->GetContentBrowserSelections(
SelectedAssets);
for (const FAssetData& Asset : SelectedAssets)
{
UE_LOG(LogTemp, Log,
TEXT("Processing: %s"),
*Asset.GetFullName());
}
}))
));
// 액터 우클릭 메뉴에 항목 추가
UToolMenu* ActorMenu = UToolMenus::Get()->ExtendMenu(
"LevelEditor.ActorContextMenu");
FToolMenuSection& ActorSection = ActorMenu->FindOrAddSection(
"MyGameActorActions");
ActorSection.AddMenuEntry(
"AlignActors",
FToolMenuEntry::InitMenuEntry(
"AlignActors",
LOCTEXT("Align", "Align to Grid"),
LOCTEXT("AlignTip",
"Aligns selected actors to the grid"),
FSlateIcon(),
FUIAction(FExecuteAction::CreateLambda([]()
{
// 선택된 액터 정렬 로직
}))
));
}
에디터 콘솔에서 ToolMenus.Edit 명령을 입력하면 현재 등록된 모든 메뉴의 이름과 구조를 확인할 수 있습니다. 또는 Widget Reflector에서 메뉴를 선택하면 메뉴 이름을 찾을 수 있습니다.
핵심 요약
- UToolMenus는 UE5의 표준 메뉴 시스템으로, 이름 기반으로 메뉴/툴바를 확장합니다.
RegisterStartupCallback으로 안전한 등록 타이밍을 보장합니다 - TCommands로 키보드 단축키를 지원하는 명령 체계를 구축하고,
FUICommandList로 실행 로직을 바인딩합니다 - FExtender는 레거시 방식이지만 특정 확장점에서 여전히 유용합니다. 새 코드에서는 UToolMenus를 우선 사용하세요
- 컨텍스트 메뉴 확장으로 콘텐츠 브라우저 에셋, 뷰포트 액터의 우클릭 메뉴에 커스텀 작업을 추가할 수 있습니다
- 에디터 콘솔의
ToolMenus.Edit과 Widget Reflector를 활용하여 메뉴 이름과 구조를 확인하세요
도전 과제
배운 내용을 직접 실습해보세요
UToolMenus::RegisterStartupCallback()에서 'LevelEditor.MainMenu' 메뉴를 확장하여 커스텀 메뉴 항목을 추가하세요. FUIAction으로 클릭 핸들러를 바인딩하고, 메뉴 아이콘과 단축키도 설정하세요.
'LevelEditor.LevelEditorToolBar.PlayToolBar' 섹션에 커스텀 툴바 버튼을 추가하세요. FSlateIcon으로 에디터 아이콘을 지정하고, ComboButton 스타일로 드롭다운 메뉴가 있는 툴바 버튼을 만드세요.
콘텐츠 브라우저의 에셋 컨텍스트 메뉴와 레벨 에디터의 Actor 컨텍스트 메뉴를 확장하세요. 선택된 에셋/Actor의 타입에 따라 동적으로 메뉴 항목이 변하는 컨텍스트 인식 메뉴 시스템을 구현하세요.