초보 코린이의 성장 일지

UE4 Button Command, Icon 본문

언리얼

UE4 Button Command, Icon

코오린이 2023. 4. 25. 19:52

에디터 카테고리 창에 제작한 버튼에다가 아이콘을 넣어줄 것이다.

1. 클래스를 하나 생성해준다.

 

더보기
#pragma once

#include "CoreMinimal.h"
/*
싱글톤으로 제작할 것이다. 싱글톤이라면 원래는 숨겨줘야한다.
하지만 SharedPtr로 생성할 것이기 때문에 외부접근할 수 있도록 열어주겠다.
다른 방법으로는 friend로 처리해줘야한다.
*/

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;
	TSharedPtr<class FSlateStyleSet> StyleSet;

public:
	FSlateIcon ToolBar_LoadMesh_Icon;

};
#include "ExampleStyle.h"
#include "Styling/SlateStyle.h"
#include "Styling/SlateStyleRegistry.h"

// 이름을 확잉하기 위해 
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.Reset();
}

FExampleStyle::FExampleStyle()
{
	StyleSet = MakeShareable(new FSlateStyleSet(StyleSetName));

	// 기준을 잡아주고, 이 기준으로부터 움직인다.
	FString path = FPaths::ProjectPluginsDir() / "Example" / "Resources";
	StyleSet->SetContentRoot(path); // 폴더를 지정해준다.

	// 이름, 사용할 파일 사진, 그릴 사이즈, return될 Icon
	RegisterIcon("ToolBar_LoadMesh", path / "Icon128.png", FVector2D(52, 52), ToolBar_LoadMesh_Icon);

	// Register 등록해준다.
	FSlateStyleRegistry::RegisterSlateStyle(*StyleSet.Get()); // *로 주소리턴 받는곳에 Get해주면 * return 받는다. (객체화도 된다.)
}

FExampleStyle::~FExampleStyle()
{
	if (StyleSet.IsValid() == false)
		return;

	FSlateStyleRegistry::UnRegisterSlateStyle(StyleSetName);
	StyleSet.Reset();
}

void FExampleStyle::RegisterIcon(const FString& InName, const FString& InPath, const FVector2D& InIconSize, FSlateIcon& OutSlateIcon)
{
	// 경로, 랜더링할 사이즈
	FSlateImageBrush* brush = new FSlateImageBrush(InPath, InIconSize);

	// Style에 들어갈 이름은 StyleSet.FName.자신의 이름으로 등록해야 언리얼에서 식별한다. ("." 이 중요)
	FString name = StyleSetName.ToString() + "." + InName;
	StyleSet->Set(FName(name), brush);// 스타일 아이콘에 이름

	// 안에 정해준 이름으로 아이콘에 적용하겠다는 의미.
	OutSlateIcon = FSlateIcon(FName(StyleSetName), FName(name));
}

1. 만들어준 클래스에 코드 작성

2. 싱글톤으로 생성하여 버튼에 등록할 아이콘 경로를 연결해주고, 사진을 가져와 사이즈를 맞추고 연결해준다.

1. 만들어준 싱글톤이 쓰일 곳에서 한번은 객체를 생성해 놓도록 바로 콜을 해준다.

2. 제거도 동일하게 해준다.

3. 이렇게 작성하는 이유로는 사용은 아직 하지 않아도 사용할 수도 있기에 생성을 시켜주고, 해제를 해준다. 그리고 사용할 곳이 생긴다면 그 곳에서 사용하면 되기 때문이다.

1. 만들어서 등록해준 아이콘을 싱글톤 생성을 해준것을 통해서 연결.

1. 아이콘 버튼에 알맞게 들어가 있는걸 볼 수 있다.


아이콘 버튼을 누르면, 파일 열기창이 뜨게되고 저장해놓은 파일을 선택하면 객체화해서 읽어 들이도록 만들어 볼 것이다.

더보기
#pragma once

#include "CoreMinimal.h"
#include "Framework/Commands/Commands.h"

class EXAMPLE_API FButtonCommand
	: public TCommands<FButtonCommand> // 부모의 공용 영역
{
public:
	FButtonCommand();
	~FButtonCommand();
    
private:
	// 델리게이션을 위한 함수
	void OnClicked_LoadMesh();  
};
#include "ButtonCommand.h"
#include "Misc/MessageDialog.h"
#include "Misc/FileHelper.h"
#include "Serialization/BufferArchive.h"
#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())
{
	Command = MakeShareable(new FUICommandList());
}

FButtonCommand::~FButtonCommand()
{
	if (Command.IsValid())
		Command.Reset();
}

void FButtonCommand::OnClicked_LoadMesh()
{
	// GetNativeWindow() 부모의 윈도우창에 접근해서 창과 알맞은 윈도우 운영체제를 return
	// 각 운영체제마다 몇 byte일지 모르기 때문에 즉 크기를 모를때는 void*로 받는다.
	IMainFrameModule& mainFrame = FModuleManager::LoadModuleChecked<IMainFrameModule>("MainFrame");
	void* handle = mainFrame.GetParentWindow()->GetNativeWindow()->GetOSWindowHandle();

	// 파일 열기창
	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);
	if (fileNames.Num() < 1) return; // 하나라도 선택안되어 있으면 return

	// 파일을 열기위한 작업
	FBufferArchive buffer;
	FFileHelper::LoadFileToArray(buffer, *fileNames[0]); // 0번으로 첫번째 선택한 파일로 지정

	// 메모리에 넣어줘야한다.
	FMemoryReader reader = FMemoryReader(buffer, true);
	reader.Seek(0); // 0 지점으로부터 읽어들인다.
	
	FStaticMesh_DetailData data; // reader통하여 읽는 단계
	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);
}

1. 버튼을 누르면 파일 창이 나오도록 연결시켜준다.

2. 그 파일을 읽어들이게 해준다.

1. 저장해 놓은 Static 파일을 읽어들이면, 출력 로그에 그 안에 들어있는 값이 출력되는걸 볼 수 있다.


 

카메라가 보는 방향으로 선을 쏴서 닿는 지점에 객체를 배치해볼 것이다.

더보기
#include "ButtonCommand.h"
#include "Misc/MessageDialog.h"
#include "Misc/FileHelper.h"
#include "Serialization/BufferArchive.h"
#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())
{
	Command = MakeShareable(new FUICommandList());
}

FButtonCommand::~FButtonCommand()
{
	if (Command.IsValid())
		Command.Reset();
}

void FButtonCommand::OnClicked_LoadMesh()
{
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);

	// 현재 활성화되어 있는 Viewport 가져오기.
	FLevelEditorViewportClient* client = (FLevelEditorViewportClient*)GEditor->GetActiveViewport()->GetClient();
	if (client == nullptr) return; 

	// 쏠 위치 시작, 끝지점 설정
	FVector start = client->GetViewLocation();
	// 쏠 방향으로 회전시켜서 보내기
	FVector end = start + client->GetViewRotation().RotateVector(FVector(10000, 0, 0));

	FHitResult hitResult;
	UWorld* world = GEditor->GetEditorWorldContext().World(); // Wolrd가 있어야 쏠 수 있기 때문에 가져와 준다.

	// 보이는거 다 추적하기.
	world->LineTraceSingleByChannel(hitResult, start, end, ECollisionChannel::ECC_Visibility);
	if (hitResult.bBlockingHit == false) // hit된게 없다면
	{
		FMessageDialog dialog;
		dialog.Debugf(FText::FromString("Can't be placed in this location."));

		return;
	}
}

1. 카메라 방향으로 하나의 선을 쏴서 맞는 부분에 객체를 생성해 주는 Line 코드를 작성해 놓았다.

2. 나중에 이용하기 위한 기본적인 코드 작성 부분.

 

https://www.youtube.com/watch?v=7HRarN5hpZ0 

 

'언리얼' 카테고리의 다른 글

UE4 Component, BackStep  (0) 2023.04.27
UE4 Tool Bar, Player  (0) 2023.04.26
UE4 Button Command  (0) 2023.04.24
UE4 Save StaticMesh  (0) 2023.04.13
UE4 StaticMesh  (0) 2023.04.12
Comments