[UE] Weapon Plugin 3: 창 내부 영역 구분하기(SWeaponLeftArea, WeaponAssetEditor)

목차
Plugins |
||||
Weapon |
||||
Resource |
||||
Icon128.png weapon_thumbnail_icon.png |
||||
Source |
||||
Weapon | ||||
SWeaponLeftArea.h .cpp 생성 Weapon.Build.cs WeaponAssetEditor.h .cpp WeaponAssetFactory.h .cpp WeaponCommand.h .cpp WeaponContextMenu.h .cpp WeaponModule.h .cpp WeaponStyle.h .cpp |
||||
Weapon Plugin 3
SCompoundWidget
SCompoundWidget
- 공간 분할해주는 역할
- 연관된 것을 묶어줄 때 사용.
- 요소들
- SAssetSearchBox
- SListView
- STextBlock
https://docs.unrealengine.com/4.27/en-US/API/Runtime/SlateCore/Widgets/SCompoundWidget/
SCompoundWidget
A CompoundWidget is the base from which most non-primitive widgets should be built.
docs.unrealengine.com
Weapon.Build.cs
Weapon.Build.cs
using UnrealBuildTool; public class Weapon : ModuleRules { public Weapon(ReadOnlyTargetRules Target) : base(Target) { PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; PrivateIncludePaths.Add(ModuleDirectory); PublicDependencyModuleNames.Add("Core"); PrivateDependencyModuleNames.Add("U2212_06");//프로젝트명 PrivateDependencyModuleNames.Add("CoreUObject"); PrivateDependencyModuleNames.Add("Engine"); PrivateDependencyModuleNames.Add("Slate"); PrivateDependencyModuleNames.Add("SlateCore"); PrivateDependencyModuleNames.Add("UnrealEd");//UFactory PrivateDependencyModuleNames.Add("EditorStyle"); PrivateDependencyModuleNames.Add("InputCore"); } }
PrivateDependencyModuleNames.Add("InputCore"); 추가
SWeaponLeftArea 생성
새 C++ 클래스 - 없음 - SWeaponLeftArea 생성

CWeaponAsset의 왼쪽에 해당되는 부분을 작업하기 위해 SWeaponLeftArea를 생성하였다.
SWeaponLeftArea.h
#pragma once #include "CoreMinimal.h" #include "Widgets/SCompoundWidget.h" #include "Widgets/Views/STableRow.h" struct FWeaponRowData { int Number; FString Name; class UCWeaponAsset* Asset; FWeaponRowData() { } FWeaponRowData(int32 InNumber, FString InName, class UCWeaponAsset* InAsset) : Number(InNumber), Name(InName), Asset(InAsset) { } static TSharedPtr<FWeaponRowData> Make(int32 InNumber, FString InName, class UCWeaponAsset* InAsset) { return MakeShareable(new FWeaponRowData(InNumber, InName, InAsset)); } }; typedef TSharedPtr<FWeaponRowData> FWeaponRowDataPtr;//실제 출력할 자료형 //한줄에 여러개 SMultiColumnTableRow class WEAPON_API SWeaponTableRow : public SMultiColumnTableRow<FWeaponRowDataPtr> { public: SLATE_BEGIN_ARGS(SWeaponTableRow) {} SLATE_ARGUMENT(FWeaponRowDataPtr, RowData) SLATE_END_ARGS() public: void Construct(const FArguments& InArgs, const TSharedRef<STableViewBase>& InOwnerTable); protected: TSharedRef<SWidget> GenerateWidgetForColumn(const FName& InColumnName) override;//STableRow.h에서 상속받아 오버라이드. private: FWeaponRowDataPtr Data;//실제로 받아서 쓸 자료형 FWeaponRowDataPtr의 변수 Data. }; class WEAPON_API SWeaponLeftArea : public SCompoundWidget { public: SLATE_BEGIN_ARGS(SWeaponLeftArea) {} SLATE_END_ARGS() public: void Construct(const FArguments& InArgs); private: TSharedRef<ITableRow> OnGenerateRow(FWeaponRowDataPtr InRow, const TSharedRef<STableViewBase>& InTable); FText OnGetAssetCount() const; private: void ReadDataAssetList(); private: TArray<FWeaponRowDataPtr> RowDatas;//데이터 자료형을 받는 배열변수 TSharedPtr<SListView<FWeaponRowDataPtr>> ListView; };
SMultiColumnTableRow을 상속받아 클래스 생성
- class WEAPON_API SWeaponTableRow
: public SMultiColumnTableRow<FWeaponRowDataPtr>
SCompoundWidget을 상속받아 클래스 생성
- class WEAPON_API SWeaponLeftArea : public SCompoundWidget
SWeaponLeftArea.cpp
#include "SWeaponLeftArea.h" #include "Weapons/CWeaponAsset.h" #include "EngineUtils.h" void SWeaponTableRow::Construct(const FArguments& InArgs, const TSharedRef<STableViewBase>& InOwnerTable) { Data = InArgs._RowData;//InArgs를 통해서 들어온다. SMultiColumnTableRow<FWeaponRowDataPtr>::Construct ( FSuperRowType::FArguments().Style(FEditorStyle::Get(), "TableView.DarkRow"), InOwnerTable ); } TSharedRef<SWidget> SWeaponTableRow::GenerateWidgetForColumn(const FName& InColumnName) { //InColumnName에 아래 Construct 내부의 SHeaderRow::Column("이름, 번호 등")이 들어간다. FString str; if (InColumnName == "Number")//InColumnName이 숫자면 str = FString::FromInt(Data->Number);//str에 숫자를 넣어준다. else if (InColumnName == "Name")//InColumnName이 이름이면 str = Data->Name;//str에 이름을 넣어준다. return SNew(STextBlock) .Text(FText::FromString(str));//출력할 문자str를 생성하여 리턴해준다. } /*모양을 디자인 해주는 역할*/ void SWeaponLeftArea::Construct(const FArguments& InArgs) { ChildSlot [ SNew(SVerticalBox) + SVerticalBox::Slot() .FillHeight(1)//1이 100%를 의미한다. 한줄을 다 채우겠다는 의미. [ SAssignNew(ListView, SListView<FWeaponRowDataPtr>)//자료형은 FWeaponRowDataPtr .HeaderRow ( SNew(SHeaderRow) + SHeaderRow::Column("Number") .DefaultLabel(FText::FromString("")) .ManualWidth(40)//칸의 너비 + SHeaderRow::Column("Name") .DefaultLabel(FText::FromString("Name")) ) .ListItemsSource(&RowDatas) .OnGenerateRow(this, &SWeaponLeftArea::OnGenerateRow)//한줄한줄 어떻게 표현할지 모양을 정해달라는 의미. ] +SVerticalBox::Slot() .AutoHeight() .VAlign(VAlign_Center) .HAlign(HAlign_Right) .Padding(FMargin(8, 2)) [ SNew(STextBlock) .Text(this, &SWeaponLeftArea::OnGetAssetCount)//const TAttribute<FText>. 여기의 text 내용이 바뀌면 자동으로 갱신해준다. Attribute의 특성 때문이다. Attribute를 함수로 줄 수 있다. 여기서는 &SWeaponLeftArea::OnGetAssetCount. ] ]; //테스트용 출력 //RowDatas.Add(FWeaponRowData::Make(1, "aaa", nullptr)); //RowDatas.Add(FWeaponRowData::Make(2, "bbb", nullptr)); //RowDatas.Add(FWeaponRowData::Make(3, "ccc", nullptr)); ReadDataAssetList(); } TSharedRef<ITableRow> SWeaponLeftArea::OnGenerateRow(FWeaponRowDataPtr InRow, const TSharedRef<STableViewBase>& InTable) { /*실제모양을 만들어 리턴*/ return SNew(SWeaponTableRow, InTable) .RowData(InRow); } void SWeaponLeftArea::ReadDataAssetList() { RowDatas.Empty();//데이터를 불러오기 전에 비워주고 시작. //"/Game"은 콘텐츠 폴더. 모든 에셋들을 찾아 objects에 리턴하겠다. ///ATL_Class는 클래스 타입, ATL_Regular는 나머지 타입(에셋을 불러와야 하므로 이것 사용). TArray<UObject*> objects; EngineUtils::FindOrLoadAssetsByPath("/Game/Weapons/", objects, EngineUtils::ATL_Regular); int32 index = 0; for (UObject* obj : objects) { UCWeaponAsset* asset = Cast<UCWeaponAsset>(obj); if (asset == nullptr) continue; FString name = asset->GetName(); RowDatas.Add(FWeaponRowData::Make(++index, name, asset));//데이터를 하나씩 넣어준다. } RowDatas.Sort([](const FWeaponRowDataPtr& A, const FWeaponRowDataPtr& B) { return A->Number < B->Number;//오름차순 정렬 }); ListView->RequestListRefresh();//다른곳에서 사용하기 때문에 재갱신를 해준다. } FText SWeaponLeftArea::OnGetAssetCount() const { FString str = FString::Printf(L"%d 에셋", RowDatas.Num()); return FText::FromString(str); }
※ 참고 - STableRow.h


SLATE_ARGUMENT | Unreal Engine Documentation
SLATE_ARGUMENT
Overload list
docs.unrealengine.com
SCustomDialog::SLATE_EVENT | Unreal Engine Documentation
SCustomDialog::SLATE_EVENT
Event triggered when the dialog is closed, either because one of the buttons is pressed, or the windows is closed.
docs.unrealengine.com
WeaponAssetEditor
WeaponAssetEditor.h
#pragma once #include "CoreMinimal.h" #include "Toolkits/AssetEditorToolkit.h" class WEAPON_API FWeaponAssetEditor : public FAssetEditorToolkit { public: static void OpenWindow(FString InAssetName = ""); static void Shutdown(); private: static TSharedPtr<FWeaponAssetEditor> Instance; private: void Open(FString InAssetName); public: void RegisterTabSpawners(const TSharedRef<FTabManager>& InTabManager) override; private: TSharedRef<SDockTab> Spawn_ListViewTab(const FSpawnTabArgs& InArgs); public: FName GetToolkitFName() const override; FText GetBaseToolkitName() const override; FString GetWorldCentricTabPrefix() const override; FLinearColor GetWorldCentricTabColorScale() const override; private: TSharedPtr<class SWeaponLeftArea> LeftArea; private: static const FName EditorName; static const FName ListViewTabId; static const FName DetailTabId; private: FReply OnClicked(); };
WeaponAssetEditor.cpp
#include "WeaponAssetEditor.h" #include "SWeaponLeftArea.h" #include "Weapons/CWeaponAsset.h" //설정한 이름들 const FName FWeaponAssetEditor::EditorName = "WeaponAssetEditor"; const FName FWeaponAssetEditor::ListViewTabId = "ListView"; const FName FWeaponAssetEditor::DetailTabId = "Details"; TSharedPtr<FWeaponAssetEditor> FWeaponAssetEditor::Instance = nullptr;//헤더에서 선언한 static 외부 초기화. void FWeaponAssetEditor::OpenWindow(FString InAssetName) { //아래의 코드 대신에 Shutdown()을 사용하면 안 된다! Shutdown()은 다른 곳에서도 콜이 되기 때문에 아래의 코드 대신에 사용하면 문제가 된다. if (Instance.IsValid()) //창이 만들어졌다면 { Instance->CloseWindow();//창을 닫는다. Instance.Reset(); Instance = nullptr; } Instance = MakeShareable(new FWeaponAssetEditor()); Instance->Open(InAssetName); } void FWeaponAssetEditor::Shutdown() { if (Instance.IsValid()) { Instance->CloseWindow(); Instance.Reset(); Instance = nullptr; } } void FWeaponAssetEditor::Open(FString InAssetName) { LeftArea = SNew(SWeaponLeftArea);//SWeaponLeftArea에서 받은 자료형을 생성하여 넣어준다. //Layout 설정 TSharedRef<FTabManager::FLayout> layout = FTabManager::NewLayout("WeaponAssetEditor_Layout") ->AddArea //전체화면의 메인 영역 ( FTabManager::NewPrimaryArea()->SetOrientation(Orient_Vertical) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.1f)//10%만 사용하겠다. ->AddTab(GetToolbarTabId(), ETabState::OpenedTab) ) ->Split ( FTabManager::NewSplitter()->SetOrientation(Orient_Horizontal) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.175f)//왼쪽 17.5% 사용 ->AddTab(ListViewTabId, ETabState::OpenedTab)//ListViewTabId ->SetHideTabWell(true) ) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.725f)//오른쪽 72.5% 사용 ->AddTab(DetailTabId, ETabState::OpenedTab)//DetailTabId ->SetHideTabWell(true) ) ) ); UCWeaponAsset* asset = NewObject<UCWeaponAsset>();//현재 없는 상태이므로 일단 빈 상태로 만들어준다. FAssetEditorToolkit::InitAssetEditor(EToolkitMode::Standalone, TSharedPtr<IToolkitHost>(), EditorName, layout, true, true, asset); } void FWeaponAssetEditor::RegisterTabSpawners(const TSharedRef<FTabManager>& InTabManager) { FAssetEditorToolkit::RegisterTabSpawners(InTabManager); FOnSpawnTab tab; tab.BindSP(this, &FWeaponAssetEditor::Spawn_ListViewTab); TabManager->RegisterTabSpawner(ListViewTabId, tab); } TSharedRef<SDockTab> FWeaponAssetEditor::Spawn_ListViewTab(const FSpawnTabArgs& InArgs) { //TSharedPtr<SDockTab> tab = SNew(SDockTab) //[ // SNew(SButton) // .OnClicked(this, &FWeaponAssetEditor::OnClicked)//OnClicked 함수 연결 // [ // SNew(STextBlock) // .Text(FText::FromString("Test")) // ] //]; //return tab.ToSharedRef(); //return SNew(SDockTab); return SNew(SDockTab) [ LeftArea.ToSharedRef() ]; } FName FWeaponAssetEditor::GetToolkitFName() const { return EditorName;//외부에서 어떤 에디터 이름을 쓸 지 정해준다. } FText FWeaponAssetEditor::GetBaseToolkitName() const { return FText::FromName(EditorName);//외부에서 어떤 에디터 이름을 쓸 지 정해준다. } FString FWeaponAssetEditor::GetWorldCentricTabPrefix() const { return EditorName.ToString();////외부에서 어떤 식별자를 쓸 지 정해준다. } FLinearColor FWeaponAssetEditor::GetWorldCentricTabColorScale() const { return FLinearColor(0, 0, 1);//파란색으로 설정. } FReply FWeaponAssetEditor::OnClicked() { GLog->Log("Test"); return FReply::Handled();//Handled()는 처리하고 끝낸다. }




실행화면

'⭐ Unreal Engine > UE Plugin - Slate UI' 카테고리의 다른 글
[UE] Weapon Plugin 6: 체크박스 만들기 (0) | 2023.06.08 |
---|---|
[UE] Weapon Plugin 5: 창 내부 Header, Child 구분하기 (0) | 2023.06.07 |
[UE] Weapon Plugin 4: 창 내에 데이터 넣어주기, 검색 기능 넣기 (0) | 2023.06.01 |
[UE] Weapon Plugin 2: 버튼 만들기, 창 띄우기 (0) | 2023.05.30 |
[UE] Weapon Plugin 1: Slate UI Plugin 만들기 (0) | 2023.05.26 |
댓글
이 글 공유하기
다른 글
-
[UE] Weapon Plugin 5: 창 내부 Header, Child 구분하기
[UE] Weapon Plugin 5: 창 내부 Header, Child 구분하기
2023.06.07 -
[UE] Weapon Plugin 4: 창 내에 데이터 넣어주기, 검색 기능 넣기
[UE] Weapon Plugin 4: 창 내에 데이터 넣어주기, 검색 기능 넣기
2023.06.01목차 Plugins Weapon Resource Icon128.pngweapon_thumbnail_icon.png Source Weapon SWeaponLeftArea.h .cppWeapon.Build.csWeaponAssetEditor.h .cppWeaponAssetFactory.h .cppWeaponCommand.h .cpp WeaponContextMenu.h .cppWeaponModule.h .cppWeaponStyle.h .cpp 무기 플러그인 만들기 SWeaponLeftArea 지난 시간에 네이밍 잘못 지어준 부분 수정. static consst FName ListViewTabId;을 LeftAreaTabId;로 변경.TSharedRef Spaw… -
[UE] Weapon Plugin 2: 버튼 만들기, 창 띄우기
[UE] Weapon Plugin 2: 버튼 만들기, 창 띄우기
2023.05.30 -
[UE] Weapon Plugin 1: Slate UI Plugin 만들기
[UE] Weapon Plugin 1: Slate UI Plugin 만들기
2023.05.26
댓글을 사용할 수 없습니다.