PART 1 · 강의 2/3

Slate 에디터 UI

UE5 에디터의 모든 UI를 구성하는 Slate 프레임워크 — 선언적 문법으로 강력한 커스텀 위젯을 구축합니다

01

Slate 프레임워크 개요

UMG의 기반이 되는 저수준 UI 시스템

Slate는 언리얼 엔진의 커스텀 UI 프레임워크입니다. UMG(Unreal Motion Graphics)가 Slate 위에 구축된 것이며, 에디터의 모든 UI(디테일 패널, 콘텐츠 브라우저, 뷰포트 등)가 Slate로 만들어져 있습니다.

특성 Slate UMG
작성 방식 C++ 선언적 문법 블루프린트 + 비주얼 디자이너
대상 에디터 UI, 도구 인게임 HUD, 메뉴
성능 높음 (직접 렌더링) 약간의 오버헤드
UObject 의존 없음 (SWidget 기반) UWidget 기반
디자이너 지원 없음 UMG Designer
Widget Reflector

에디터 메뉴에서 Tools > Debug > Widget Reflector를 열면 현재 에디터 UI의 Slate 위젯 계층 구조를 실시간으로 확인할 수 있습니다. 에디터 확장 개발의 필수 도구입니다.

02

SNew와 SAssignNew — 선언적 위젯 생성

Slate의 핵심 매크로와 선언적 문법 마스터하기

Slate는 선언적 문법(Declarative Syntax)을 사용합니다. SNewSAssignNew 매크로로 위젯 트리를 구축합니다.

SNew vs SAssignNew

매크로 반환 타입 용도
SNew(WidgetType) TSharedRef<SWidget> 위젯 생성 (참조 저장 불필요)
SAssignNew(Var, WidgetType) TSharedRef<SWidget> 위젯 생성 + 멤버 변수에 할당

기본 위젯 생성 예제

C++ Slate // 간단한 텍스트 블록 SNew(STextBlock) .Text(FText::FromString(TEXT("Hello, Slate!"))) .Font(FCoreStyle::GetDefaultFontStyle("Bold", 16)) .ColorAndOpacity(FSlateColor(FLinearColor::White)); // 버튼 위젯 SNew(SButton) .OnClicked(this, &SMyWidget::OnButtonClicked) .Content() [ SNew(STextBlock) .Text(LOCTEXT("ClickMe", "Click Me")) ]; // SAssignNew로 나중에 참조할 위젯 저장 TSharedPtr<SEditableTextBox> MyTextBox; SAssignNew(MyTextBox, SEditableTextBox) .HintText(LOCTEXT("Hint", "Enter text..."));

위젯 계층 구조 (슬롯)

C++ Slate - 레이아웃 // 수직 박스 레이아웃 SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() .Padding(5.0f) [ SNew(STextBlock) .Text(LOCTEXT("Title", "Panel Title")) ] + SVerticalBox::Slot() .FillHeight(1.0f) .Padding(5.0f) [ SNew(SBorder) .BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder")) [ SNew(STextBlock) .Text(LOCTEXT("Content", "Content Area")) ] ] + SVerticalBox::Slot() .AutoHeight() .HAlign(HAlign_Right) .Padding(5.0f) [ SNew(SButton) .Text(LOCTEXT("OK", "OK")) ];
슬롯 사이징 규칙

AutoHeight()는 자식 위젯의 크기에 맞추고, FillHeight(N)은 남은 공간을 비율로 분배합니다. SHorizontalBox에서는 AutoWidth()FillWidth(N)을 사용합니다.

03

핵심 Slate 위젯

에디터 도구 개발에 자주 사용하는 위젯들

위젯 기능 주요 어트리뷰트
STextBlock 텍스트 표시 .Text(), .Font(), .ColorAndOpacity()
SEditableTextBox 텍스트 입력 .Text(), .OnTextChanged(), .HintText()
SButton 클릭 가능 버튼 .OnClicked(), .Text(), .IsEnabled()
SCheckBox 체크박스 .IsChecked(), .OnCheckStateChanged()
SVerticalBox 수직 레이아웃 Slot().AutoHeight(), .FillHeight()
SHorizontalBox 수평 레이아웃 Slot().AutoWidth(), .FillWidth()
SScrollBox 스크롤 영역 .Orientation(), 자식 위젯
SSplitter 분할 패널 .Orientation(), Slot()
SBorder 테두리/배경 .BorderImage(), .Padding()
SImage 이미지 표시 .Image(), .ColorAndOpacity()
SListView 리스트 뷰 .ListItemsSource(), .OnGenerateRow()
SComboBox 드롭다운 .OptionsSource(), .OnSelectionChanged()

어트리뷰트 바인딩 패턴

C++ Slate - 어트리뷰트 바인딩 // 1. 정적 값 .Text(LOCTEXT("Static", "Hello")) // 2. 델리게이트 바인딩 (매 프레임 호출) .Text(this, &SMyWidget::GetStatusText) // 3. TAttribute 바인딩 .Visibility(TAttribute<EVisibility>::Create( TAttribute<EVisibility>::FGetter::CreateLambda([this]() { return bShowWidget ? EVisibility::Visible : EVisibility::Collapsed; }))) // 4. 람다 이벤트 핸들러 .OnClicked_Lambda([]() { UE_LOG(LogTemp, Log, TEXT("Button Clicked!")); return FReply::Handled(); })
04

커스텀 Slate 위젯 만들기

SCompoundWidget을 상속하여 재사용 가능한 위젯 작성

커스텀 위젯은 SCompoundWidget을 상속하여 만듭니다. SLATE_BEGIN_ARGS / SLATE_END_ARGS 매크로로 위젯의 인자를 선언합니다.

SMyToolPanel.h #pragma once #include "CoreMinimal.h" #include "Widgets/SCompoundWidget.h" class SMyToolPanel : public SCompoundWidget { public: SLATE_BEGIN_ARGS(SMyToolPanel) : _Title(LOCTEXT("DefaultTitle", "Tool Panel")) , _bShowHeader(true) {} // 어트리뷰트: TAttribute로 동적 바인딩 가능 SLATE_ATTRIBUTE(FText, Title) // 인자: 생성 시 한 번만 설정 SLATE_ARGUMENT(bool, bShowHeader) // 이벤트: 델리게이트 바인딩 SLATE_EVENT(FOnClicked, OnApplyClicked) // 기본 슬롯 (자식 위젯) SLATE_DEFAULT_SLOT(FArguments, Content) SLATE_END_ARGS() void Construct(const FArguments& InArgs); private: FReply HandleApplyClicked(); FOnClicked OnApplyClicked; };
SMyToolPanel.cpp #include "SMyToolPanel.h" void SMyToolPanel::Construct(const FArguments& InArgs) { OnApplyClicked = InArgs._OnApplyClicked; ChildSlot [ SNew(SVerticalBox) // 헤더 + SVerticalBox::Slot() .AutoHeight() .Padding(8.0f) [ SNew(STextBlock) .Text(InArgs._Title) .Font(FCoreStyle::GetDefaultFontStyle("Bold", 18)) .Visibility(InArgs._bShowHeader ? EVisibility::Visible : EVisibility::Collapsed) ] // 콘텐츠 영역 + SVerticalBox::Slot() .FillHeight(1.0f) .Padding(8.0f) [ InArgs._Content.Widget ] // 하단 버튼 + SVerticalBox::Slot() .AutoHeight() .HAlign(HAlign_Right) .Padding(8.0f) [ SNew(SButton) .Text(LOCTEXT("Apply", "Apply")) .OnClicked(this, &SMyToolPanel::HandleApplyClicked) ] ]; } FReply SMyToolPanel::HandleApplyClicked() { if (OnApplyClicked.IsBound()) { return OnApplyClicked.Execute(); } return FReply::Handled(); }

커스텀 위젯 사용

C++ 사용 예 SNew(SMyToolPanel) .Title(LOCTEXT("MyTool", "My Custom Tool")) .bShowHeader(true) .OnApplyClicked_Lambda([]() { // Apply 로직 return FReply::Handled(); }) [ // 콘텐츠 슬롯에 자식 위젯 배치 SNew(STextBlock) .Text(LOCTEXT("Body", "Tool content goes here")) ];
SLATE 매크로 정리
매크로 용도 바인딩
SLATE_ATTRIBUTE 동적으로 변할 수 있는 값 TAttribute (매 프레임 평가)
SLATE_ARGUMENT 생성 시 한 번 설정되는 값 직접 값 전달
SLATE_EVENT 콜백 델리게이트 FOnClicked 등
SLATE_DEFAULT_SLOT 단일 자식 위젯 슬롯 [] 연산자로 배치
SLATE_NAMED_SLOT 이름이 있는 위젯 슬롯 .SlotName() 으로 배치
05

에디터 탭 등록하기

FGlobalTabmanager로 독립 에디터 탭 생성

커스텀 Slate 위젯을 에디터 탭으로 등록하면 에디터에서 도킹 가능한 독립 패널이 됩니다.

에디터 모듈에서 탭 등록 static const FName MyToolTabName("MyToolTab"); void FMyGameEditorModule::StartupModule() { // 탭 스포너 등록 FGlobalTabmanager::Get()->RegisterNomadTabSpawner( MyToolTabName, FOnSpawnTab::CreateRaw( this, &FMyGameEditorModule::SpawnMyToolTab)) .SetDisplayName(LOCTEXT("TabTitle", "My Tool")) .SetMenuType(ETabSpawnerMenuType::Hidden); } void FMyGameEditorModule::ShutdownModule() { FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(MyToolTabName); } TSharedRef<SDockTab> FMyGameEditorModule::SpawnMyToolTab( const FSpawnTabArgs& Args) { return SNew(SDockTab) .TabRole(NomadTab) [ SNew(SMyToolPanel) .Title(LOCTEXT("Title", "My Editor Tool")) ]; } // 탭 열기 (메뉴나 버튼에서 호출) FGlobalTabmanager::Get()->TryInvokeTab(MyToolTabName);
NomadTab vs DocumentTab

NomadTab은 에디터 어디에나 도킹할 수 있는 독립 탭입니다. DocumentTab은 에셋 에디터처럼 중앙 영역에 배치되는 문서 탭입니다. 도구 패널에는 NomadTab을 사용하세요.

SUMMARY

핵심 요약

  • Slate는 UE5 에디터 UI의 기반 프레임워크이며, C++ 선언적 문법으로 위젯 트리를 구축합니다
  • SNew로 위젯을 생성하고, SAssignNew로 참조를 보존합니다. +Slot()으로 자식 위젯을 배치합니다
  • SCompoundWidget을 상속하여 커스텀 위젯을 만들고, SLATE_ATTRIBUTE, SLATE_ARGUMENT, SLATE_EVENT로 인터페이스를 정의합니다
  • FGlobalTabmanager로 에디터 도킹 탭을 등록하여 독립 도구 패널을 생성할 수 있습니다
  • Widget Reflector로 기존 에디터 UI의 Slate 구조를 분석하여 학습하세요
PRACTICE

도전 과제

배운 내용을 직접 실습해보세요

실습 1: Slate 위젯으로 에디터 탭 생성

FGlobalTabmanager::Get()->RegisterNomadTabSpawner()로 커스텀 에디터 탭을 등록하세요. SVerticalBox, STextBlock, SButton 위젯을 사용하여 간단한 도구 패널 UI를 구성하고, 버튼 클릭 시 Output Log에 메시지를 출력하세요.

실습 2: Slate 레이아웃과 스타일링

SHorizontalBox, SSplitter, SScrollBox를 사용하여 좌측 목록 + 우측 상세 뷰의 2단 레이아웃을 구성하세요. FEditorStyle과 FSlateStyleSet을 활용하여 UE5 에디터와 일관된 스타일을 적용하세요.

심화 과제: 커스텀 에디터 윈도우 프레임워크

SWindow를 사용하여 독립 에디터 윈도우를 생성하는 프레임워크를 구현하세요. 윈도우 크기 저장/복원, 도킹 지원, 커스텀 타이틀바, 키보드 단축키 바인딩을 포함하는 완성도 높은 에디터 도구 윈도우를 만드세요.