[UE] Tool Bar 아이콘 만들기

목차
Plugins | ||
Example | ||
ButtonCommand.h .cpp Example.Build.cs ExampleConsoleCommand.h .cpp ExampleDebuggerCategory.h .cpp ExampleModule.h .cpp ExampleStyle.h.cpp 생성 StaticMesh_Detail.h .cpp |
||
Source | ||
Utilities | ||
CHelper.h CLog.h .cpp |
||
Global.h CStaticMesh.h .cpp .Build.cs |
||
.uproject | ||
Tool Bar 아이콘 만들기
Plugin 아이콘 저장위치

Example.Build.cs
Example.Build.cs
더보기
using UnrealBuildTool; public class Example : ModuleRules { public Example(ReadOnlyTargetRules Target) : base(Target) //public은 외부에 공개 { PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; PublicIncludePaths.Add(ModuleDirectory); PublicDependencyModuleNames.Add("Core"); PrivateDependencyModuleNames.Add("U2212_05"); //본인 모델은 private PrivateDependencyModuleNames.Add("CoreUObject"); PrivateDependencyModuleNames.Add("Engine"); PrivateDependencyModuleNames.Add("Slate"); PrivateDependencyModuleNames.Add("SlateCore"); PrivateDependencyModuleNames.Add("GameplayDebugger"); PrivateDependencyModuleNames.Add("DesktopPlatform"); PrivateDependencyModuleNames.Add("MainFrame"); PrivateDependencyModuleNames.Add("EditorStyle");//ExampleModule.cpp의 ToolBar(=ButtonCommand)를 위해 추가 PrivateDependencyModuleNames.Add("UnrealEd"); } }
추가
- PrivateDependencyModuleNames.Add("UnrealEd");
Static 변수를 외부에서 초기화해야 하는 이유
static은 클래스 내부가 아니라 클래스 공용에서 객체화된다.
ExampleStyle 생성
싱글톤을 사용하였다. 싱글톤은 멀티 스레드 상황에서 문제가 될 수 있다는 단점이 있으므로 다른 대안의 디자인 패턴이 있으면 사용을 지양하자.
싱글톤을 사용할 때는 생성과 소멸 시점을 명확히 지정해서 꼭 규칙을 지켜서 사용하자.
- 싱글톤을 사용할 때는 Get()으로 초기화 하는것보다 외부에서 Create()으로 생성시켜준 후 Get()을 사용하는게 좋다. 이렇게 외부에서 생성시켜주면 생성 시점이 특정이되어 좋다.
- 소멸도 같은 의미로 Delete()로 빼주는게 좋다.
ExampleStyle.h
더보기
#pragma once #include "CoreMinimal.h" class EXAMPLE_API FExampleStyle { public: static TSharedPtr<FExampleStyle> Get(); static void Shutdown(); private: static TSharedPtr<FExampleStyle> Instance; public: FExampleStyle(); ~FExampleStyle(); private: void RegisterIcon(const FString& InName, const FString& InPath, const FVector2D& InIconSize, FSlateIcon& OutSlateIcon); private: static const FName StyleSetName;//이름을 찾기 쉽게 static으로 만든 후 .cpp에서 이름을 지어준다. TSharedPtr<class FSlateStyleSet> StyleSet; public: FSlateIcon ToolBar_LoadMesh_Icon; };
ExampleStyle.cpp
더보기
#include "ExampleStyle.h" #include "Styling/SlateStyle.h" #include "Styling/SlateStyleRegistry.h" //등록객체 관리 //static 함수는 클래스 내부가 아닌 공용에서 객체화되기 때문에 여기서 초기값을 넣어준다.이름을 찾기 쉽게 헤더가 아닌 .cpp에 이름을 지어준다. const FName FExampleStyle::StyleSetName = "ExampleStyle"; TSharedPtr<FExampleStyle> FExampleStyle::Instance = nullptr; TSharedPtr<FExampleStyle> FExampleStyle::Get() { if (Instance == nullptr) Instance = MakeShareable(new FExampleStyle()); return Instance; } void FExampleStyle::Shutdown() { if (Instance.IsValid())//Instance가 있다면 Instance.Reset();//Instance를 리셋해준다. } FExampleStyle::FExampleStyle() { StyleSet = MakeShareable(new FSlateStyleSet(StyleSetName)); FString path = FPaths::ProjectPluginsDir() / "Example" / "Resources"; StyleSet->SetContentRoot(path); RegisterIcon("ToolBar_LoadMesh", path / "Icon128.png", FVector2D(52, 52), ToolBar_LoadMesh_Icon); FSlateStyleRegistry::RegisterSlateStyle(*StyleSet.Get());//StyleSet을 등록시켜준다. } FExampleStyle::~FExampleStyle() { if (StyleSet.IsValid() == false) return; FSlateStyleRegistry::UnRegisterSlateStyle(StyleSetName);//StyleSet 등록을 해제해준다. StyleSet.Reset(); //StyleSet을 지워준다. } void FExampleStyle::RegisterIcon(const FString& InName, const FString& InPath, const FVector2D& InIconSize, FSlateIcon& OutSlateIcon) { FSlateImageBrush* brush = new FSlateImageBrush(InPath, InIconSize); FString name = StyleSetName.ToString() + "." + InName; StyleSet->Set(FName(name), brush); OutSlateIcon = FSlateIcon(FName(StyleSetName), FName(name));//StyleSetName에 name 이름으로 아이콘을 등록한다. }
ButtonCommand
ButtonCommand.h
더보기
#pragma once #include "CoreMinimal.h" #include "Framework/Commands/Commands.h" class EXAMPLE_API FButtonCommand : public TCommands<FButtonCommand> { public: FButtonCommand(); ~FButtonCommand(); public: void RegisterCommands() override; public: TSharedPtr<FUICommandList> Command; public: TSharedPtr<FUICommandInfo> LoadMesh; private: void OnClicked_LoadMesh(); };
변경사항 없음.
ButtonCommand.cpp
더보기
#include "ButtonCommand.h" #include "Misc/MessageDialog.h" #include "Misc/FileHelper.h" #include "Serialization/BufferArchive.h" //행렬화 관련 헤더. Buffer를 활용하여 내보내는데 필요하다. #include "DesktopPlatformModule.h" #include "Interfaces/IMainFrameModule.h" #include "StaticMesh_Detail.h" #include "Editor.h" #include "LevelEditorViewport.h" FButtonCommand::FButtonCommand() : TCommands("ToolBar_Buttons", FText(), NAME_None,FEditorStyle::GetStyleSetName())//oolBar_Buttons는 총괄 객체의 이름 { Command = MakeShareable(new FUICommandList()); } FButtonCommand::~FButtonCommand() { if (Command.IsValid()) Command.Reset(); } void FButtonCommand::RegisterCommands() { #define LOCTEXT_NAMESPACE "" UI_COMMAND(LoadMesh, "LoadMesh", "", EUserInterfaceActionType::Button, FInputChord());//q버튼, 체크박스, 라디오버튼 등 원는 방식으로 버튼을 만들어준다. #undef LOCTEXT_NAMESPACE Command->MapAction(LoadMesh, FExecuteAction::CreateRaw(this, &FButtonCommand::OnClicked_LoadMesh));//LoadMesh실행을 위해 OnClicked_LoadMesh를ExecuteAction::CreateRaw으로 연결해준다. } void FButtonCommand::OnClicked_LoadMesh() { IMainFrameModule& mainFrame = FModuleManager::LoadModuleChecked<IMainFrameModule>("MainFrame"); void* handle = mainFrame.GetParentWindow()->GetNativeWindow()->GetOSWindowHandle();//NativeWindow()가 실제 창 객체. GetOSWindowHandle()는 각 운영체제에 맞는 WindowHandle를 리턴해준다.//WindowHandle식별자는 dword x64면 가변형이다. 4byte로 처리가능하면 4byte, 불가능하면 8byte이다. FString path; FPaths::GetPath(path); TArray<FString> fileNames; IDesktopPlatform* platform = FDesktopPlatformModule::Get(); platform->OpenFileDialog(handle, "Open Mesh File", path, "", "Mesh Binary File(*.bin)|*.bin", EFileDialogFlags::None, fileNames);//title은 파일 이름, EFileDialogFlags는 공유속성(None으로 설정하였다) if (fileNames.Num() < 1) return; FBufferArchive buffer; FFileHelper::LoadFileToArray(buffer, *fileNames[0]);//파일을 buffer에 읽어놓는다. FMemoryReader reader = FMemoryReader(buffer, true); reader.Seek(0); //reader로 파일을 읽음 FStaticMesh_DetailData data; reader << data; reader.FlushCache(); reader.Close(); GLog->Logf(L"Vertex Count : %d", data.Positions.Num()); GLog->Logf(L"Triangle Count : %d", data.Indices.Num() / 3); GLog->Logf(L"Extent : %s", *data.Extent.ToString()); GLog->Logf(L"Radius : %f", data.Radius); FString text; for (int32 i = 0; i < data.Positions.Num(); i++) { text.Append(data.Positions[i].ToString() + ", "); text.Append(data.Normals[i].ToString() + ", "); text.Append(data.Uvs[i].ToString() + ", "); text.Append(data.Colors[i].ToString() + "\r\n"); } FString textFileName = FPaths::GetBaseFilename(fileNames[0], false); FString textSaveName = textFileName + "_Copied.csv"; FFileHelper::SaveStringToFile(text, *textSaveName); //FLevelEditorViewportClient* client = dynamic_cast<FLevelEditorViewportClient*>(GEditor->GetActiveViewport()->GetClient()); //현재 활성화된 뷰포트 FLevelEditorViewportClient* client = (FLevelEditorViewportClient*)GEditor->GetActiveViewport()->GetClient(); //현재 활성화된 뷰포트 if (client == nullptr) return; //clinet가 없다면 리턴 FVector start = client->GetViewLocation(); FVector end = start + client->GetViewRotation().RotateVector(FVector(1000, 0, 0)); FHitResult hitResult; UWorld* world = GEditor->GetEditorWorldContext().World(); world->LineTraceSingleByChannel(hitResult, start, end, ECollisionChannel::ECC_Visibility);//보이는것 다 수정. if(hitResult.bBlockingHit == false) { FMessageDialog dialog; dialog.Debugf(FText::FromString("Can't be placed in this location.")); return; } }
함수 정의
- void FButtonCommand::OnClicked_LoadMesh()
ExampleModule
ExampleModule.h
더보기
#pragma once #include "CoreMinimal.h" class FExampleModule : public IModuleInterface { public: virtual void StartupModule() override; virtual void ShutdownModule() override; private: TSharedPtr<class FExampleConsoleCommand> ConsoleCommand; private: TSharedPtr<FExtender> Extender;//확장을 위한 Extender private: void AddToolBar(class FToolBarBuilder& InBuilder);//버튼을 추가하는 역할 };
변경사항 없음.
ExampleModule.cpp
더보기
#include "ExampleModule.h" #include "ExampleStyle.h" #include "ExampleDubuggerCategory.h" #include "ExampleConsoleCommand.h" #include "StaticMesh_Detail.h" #include "ButtonCommand.h" #include "U2212_05/CStaticMesh.h" #include "GameplayDebugger.h" #include "LevelEditor.h" #define LOCTEXT_NAMESPACE "FExampleModule" IMPLEMENT_MODULE(FExampleModule, Example)//모듈의 시작점을 알려준다. void FExampleModule::StartupModule() { FExampleStyle::Get(); //싱글톤 객체 생성 //Debugger { IGameplayDebugger::FOnGetCategory category; category.BindStatic(&FExampleDubuggerCategory::MakeInstance); IGameplayDebugger::Get().RegisterCategory("Example", category, EGameplayDebuggerCategoryState::EnabledInGameAndSimulate, 5); //5번 슬롯 할당 IGameplayDebugger::Get().NotifyCategoriesChanged(); } //Console Command { ConsoleCommand = MakeShareable(new FExampleConsoleCommand()); } //Property Editor - StaticMeshActor { FOnGetDetailCustomizationInstance instance; //싱글톤 instance.BindStatic(&FStaticMesh_Detail::MakeInstance);//Bind로 묶어준다.//StaticMeshActor_Detail.h에서 static으로 만든 MakeInstance 사용. FPropertyEditorModule& prop = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor"); prop.RegisterCustomClassLayout(ACStaticMesh::StaticClass()->GetFName(), instance); } //ToolBar(=ButtonCommand) { FButtonCommand::Register(); Extender = MakeShareable(new FExtender());//Extender 생성 FToolBarExtensionDelegate toolBar; toolBar.BindRaw(this, &FExampleModule::AddToolBar);//toolBar와 AddToolBar를 연결 Extender->AddToolBarExtension("Compile", EExtensionHook::Before, FButtonCommand::Get().Command, toolBar); FLevelEditorModule& levelEditor = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor");//LevelEditorModule을 불러온다. levelEditor.GetToolBarExtensibilityManager()->AddExtender(Extender);//levelEditor에 Extender를 추가 } } void FExampleModule::ShutdownModule() { if (IGameplayDebugger::IsAvailable()) IGameplayDebugger::Get().UnregisterCategory("Example"); if (ConsoleCommand.IsValid()) ConsoleCommand.Reset(); //스마트포인터를 제거할 수 있도록 Reset()을 콜 해준다. 자동화가 문제가 되는경우가 있으므로 넣어준다. FExampleStyle::Shutdown(); //싱글톤 객체 제거 } void FExampleModule::AddToolBar(FToolBarBuilder& InBuilder) { FString name = TEXT("메시"); InBuilder.AddSeparator(); //언리얼 에디터 툴바의 구분선(|) InBuilder.AddToolBarButton ( FButtonCommand::Get().LoadMesh, "LoadMesh", //InExtensionHook FText::FromString(name), //InLabelOverride FText::FromString("Load Mesh Data"), //InToolTipOverride FExampleStyle::Get()->ToolBar_LoadMesh_Icon //아이콘 ); } #undef LOCTEXT_NAMESPACE
헤더 추가
- #include "ExampleStyle.h"
void FExampleModule::StartupModule()
- 싱글톤 객체 생성
- FExampleStyle::Get();
void FExampleModule::ShutdownModule()
- 싱글톤 객체 제거
- FExampleStyle::Shutdown();
실행화면




'⭐ Unreal Engine > UE Plugin - Basic' 카테고리의 다른 글
[UE] 툴바 아이콘을 사용하여 뷰포트에 매쉬 배치하기 (0) | 2023.04.26 |
---|---|
[UE] 툴바 만들기(ButtonCommand), 문자(MBCS, Unicode) (0) | 2023.04.18 |
[UE] Plugin (Button Command) (0) | 2023.04.14 |
[UE] Plugin (Save StaticMesh .csv) (0) | 2023.04.13 |
[UE] Plugin (Save StaticMesh & RenderData, LOD) (0) | 2023.04.12 |
댓글
이 글 공유하기
다른 글
-
[UE] 툴바 아이콘을 사용하여 뷰포트에 매쉬 배치하기
[UE] 툴바 아이콘을 사용하여 뷰포트에 매쉬 배치하기
2023.04.26 -
[UE] 툴바 만들기(ButtonCommand), 문자(MBCS, Unicode)
[UE] 툴바 만들기(ButtonCommand), 문자(MBCS, Unicode)
2023.04.18 -
[UE] Plugin (Button Command)
[UE] Plugin (Button Command)
2023.04.14 -
[UE] Plugin (Save StaticMesh .csv)
[UE] Plugin (Save StaticMesh .csv)
2023.04.13
댓글을 사용할 수 없습니다.