Slate 기초와 Dockable Editor Tab 만들기
23강. Slate 기초와 Dockable Editor Tab 만들기
1. 이번 강의에서 해결할 문제
검사 결과가 로그에만 있으면 에셋 선택, 재검사, 오류 이동을 한 흐름으로 처리하기 어렵습니다. 임시 SWindow를 매번 만들면 Editor 레이아웃에 저장되지 않고 중복 창 관리도 필요합니다. Editor 작업 도구는 Docking과 재호출이 가능한 Tab으로 제공하는 편이 자연스럽습니다.
2. 학습 목표
3. 핵심 개념
Slate는 Unreal Editor UI의 C++ 기반 선언형 프레임워크입니다. TSharedRef·TSharedPtr로 Widget 수명을 관리하며, UObject Garbage Collection과 다른 소유권 모델을 사용합니다. Dockable Tool은 FGlobalTabmanager에 Tab Spawner를 등록하고 SDockTab 안에 전용 Widget을 배치합니다.
이 강의는 검사 실행 버튼과 상태 문구만 만들고, Asset Registry 결과 목록은 27강에서 연결합니다.
4. 단계별 실습
#pragma once
#include "Widgets/SCompoundWidget.h"
class SDataGuardPanel final : public SCompoundWidget
{
public:
SLATE_BEGIN_ARGS(SDataGuardPanel) {}
SLATE_END_ARGS()
void Construct(const FArguments& InArgs);
private:
FReply HandleRunValidation();
FText GetStatusText() const;
int32 LastIssueCount = 0;
};
#include "Widgets/SDataGuardPanel.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Layout/SBorder.h"
#include "Widgets/Layout/SBox.h"
#include "Widgets/Text/STextBlock.h"
#define LOCTEXT_NAMESPACE "SDataGuardPanel"
void SDataGuardPanel::Construct(const FArguments& InArgs)
{
ChildSlot
[
SNew(SBorder)
.Padding(16.0f)
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.AutoHeight()
[
SNew(STextBlock)
.Text(LOCTEXT("Title", "Data Guard"))
]
+ SVerticalBox::Slot()
.AutoHeight()
.Padding(0.0f, 12.0f)
[
SNew(SButton)
.Text(LOCTEXT("Run", "Run Project Validation"))
.ToolTipText(LOCTEXT("RunTip", "Scan configured project assets."))
.OnClicked(this, &SDataGuardPanel::HandleRunValidation)
]
+ SVerticalBox::Slot()
.AutoHeight()
[
SNew(STextBlock)
.Text(this, &SDataGuardPanel::GetStatusText)
]
]
];
}
FReply SDataGuardPanel::HandleRunValidation()
{
LastIssueCount = 0;
return FReply::Handled();
}
FText SDataGuardPanel::GetStatusText() const
{
return FText::Format(
LOCTEXT("Status", "Last scan: {0} issues"),
FText::AsNumber(LastIssueCount));
}
#undef LOCTEXT_NAMESPACE
Module에 Tab을 등록합니다.
#include "Widgets/Docking/SDockTab.h"
#include "Widgets/SDataGuardPanel.h"
namespace DataGuardTabs
{
static const FName MainTab(TEXT("DataGuard.Main"));
}
void FDataGuardEditorModule::StartupModule()
{
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(
DataGuardTabs::MainTab,
FOnSpawnTab::CreateRaw(this, &FDataGuardEditorModule::SpawnMainTab))
.SetDisplayName(LOCTEXT("DataGuardTab", "Data Guard"))
.SetMenuType(ETabSpawnerMenuType::Hidden);
UToolMenus::RegisterStartupCallback(/* 22강과 동일 */);
}
TSharedRef<SDockTab> FDataGuardEditorModule::SpawnMainTab(
const FSpawnTabArgs& Args)
{
return SNew(SDockTab)
.TabRole(ETabRole::NomadTab)
[
SNew(SDataGuardPanel)
];
}
void FDataGuardEditorModule::OpenDataGuard()
{
FGlobalTabmanager::Get()->TryInvokeTab(DataGuardTabs::MainTab);
}
void FDataGuardEditorModule::ShutdownModule()
{
FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(
DataGuardTabs::MainTab);
// 22강의 ToolMenus 해제도 그대로 수행합니다.
}
Build.cs의 Slate와 SlateCore는 Private Dependency로 유지합니다. Public API가 Slate Widget을 노출하지 않기 때문입니다.
5. 코드가 동작하는 이유
Tab Manager가 ID와 생성 Delegate를 보관하고, 사용자가 메뉴를 실행할 때 TryInvokeTab이 이미 열린 탭을 활성화하거나 새 탭을 생성합니다. Panel은 Slate 공유 포인터 수명 안에서만 존재하고 Module은 Spawner 등록 수명을 책임집니다.
6. 자주 하는 실수와 해결법
7. 직접 실습
8. 이해 점검 질문 3개
9. 핵심 요약
Slate 기초와 Dockable Editor Tab 만들기 미니 퀴즈
선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.
학습을 마쳤나요?
직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.