天天看点

Unreal Engine 4:学习笔记(十三)Slate

Slate是使用C++代码来实现Widget功能的框架。Slate中已经有定义好的Widget元素可以使用,也可以使用这些Widget元素创建新的Widget。

一、引入对Slate库的依赖

在项目中要使用Slate框架,首先需要引入对Slate库的依赖。可以在*.Build.cs中添加对InputCore、Slate、SlateCore的依赖:

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
           

二、将Widget添加到Viewport或从Viewport中删除

使用

GameViewportClient::AddViewportWidgetContent()将Widget添加到

Viewport中,主要有以下三种方式:

TSharedPtr<MyWidget> MyWidgetPtr;

//--1
GEngine->GameViewport->AddViewportWidgetContent(
    SNew(MyWidgetPtr.ToSharedRef())
);

//--2
GEngine->GameViewport->AddViewportWidgetContent(
    SNew(SWeakWidget)
    .PossiblyNullContent(MyWidgetClass)
);

//--3
GEngine->GameViewport->AddViewportWidgetContent(
    SAssignNew(MyWidgetPtr, SWeakWidget)
    .PossiblyNullContent(MyWidgetClass)
);
           

使用

GameViewportClient::RemoveViewportWidgetContent()将Widget删除

GEngine->GameViewport->RemoveViewportWidgetContent(
    SNew(MyWidgetPtr.ToSharedRef())
);
           

 使用

GameViewportClient::RemoveAllViewportWidgets()将Widget全部删除

GEngine->GameViewport->RemoveAllViewportWidgets();
           

 三、Widget类型

Leaf Widgets - 没有子slot。比如STextBlock

Panels - 可有多个子slot。比如SOverlay、SHorizontalBox。使用SOverlay::Slot()、SHorizontalBox::Slot()添加子slot

Compound Widgets - 只有一个子slot。比如SEditableTextBox。使用SEditableTextBox.ChildSlot添加子slot

四、创建Widget的方式

TSharedRef<SButton> MyButton = SNew(SButton);
   or
TSharedPtr<SButton> MyButton;
SAssignNew( MyButton, SButton );
           

五、一个简单的例子

创建一个Widget,包含一个Button和一个TextBox,代码如下:

// StandardSlateWidget.h
#pragma once
#include "CoreMinimal.h"
#include "Widgets/SCompoundWidget.h"
#include "Widgets/Input/SEditableTextBox.h"
#include "Templates/SharedPointer.h"

class ANDROIDPROJECT1_API SStandardSlateWidget : public SCompoundWidget
{
public:
	SLATE_BEGIN_ARGS(SStandardSlateWidget)
	{}
	SLATE_ARGUMENT(TWeakObjectPtr<class AStandardHUD>, OwnerHUDArg);
	SLATE_END_ARGS()

	void Construct(const FArguments& InArgs);

private:
	TWeakObjectPtr<class AStandardHUD> OwnerHUD;

	FReply Btn_OnClicked();

	FText MyText;
	FText GetText() const;
	void OnTextChanged(const FText& Text);
};
           
// StandardSlateWidget.cpp
#include "StandardSlateWidget.h"
#include "SlateOptMacros.h"

#include "Widgets/SBoxPanel.h"
#include "Widgets/SOverlay.h"
#include "Widgets/Input/SEditableTextBox.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Text/STextBlock.h"
#include "Widgets/DeclarativeSyntaxSupport.h"

#include "Engine/Engine.h"

BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION

// ++ This is needed in order to use the localization macro LOCTEXT
#define LOCTEXT_NAMESPACE "SStandardSlateWidget"

FReply SStandardSlateWidget::Btn_OnClicked()
{
	FString MsgText = FString(TEXT("click me"));
	//GEngine->AddOnScreenDebugMessage(-1, 50.f, FColor::Blue, MsgText);
	//UE_LOG(LogTemp, Log, TEXT("MsgText=%s"), *MsgText);

	MsgText = GetText().ToString() + FString(TEXT("-")) + MsgText;
	MyText = FText::FromString(MsgText);

	return FReply::Handled();
};

FText SStandardSlateWidget::GetText() const
{
	return MyText;
}

void SStandardSlateWidget::OnTextChanged(const FText& InText)
{
	MyText = InText;

	GEngine->AddOnScreenDebugMessage(-1, 50.f, FColor::Blue, InText.ToString());
};

void SStandardSlateWidget::Construct(const FArguments& InArgs)
{
	OwnerHUD = InArgs._OwnerHUDArg;

	ChildSlot
	.VAlign(VAlign_Fill)
	.HAlign(HAlign_Fill)
	[
		SNew(SOverlay)
		+ SOverlay::Slot()
		.VAlign(VAlign_Top)
		.HAlign(HAlign_Fill)
		[
			SNew(SHorizontalBox)
			+ SHorizontalBox::Slot()
			.Padding(1.0f)
			.HAlign(HAlign_Fill)
			[
				SNew(SButton)
				.OnClicked(this, &SStandardSlateWidget::Btn_OnClicked)
				.Content()
				[
					SNew(STextBlock)
					.Text(LOCTEXT("ClickButton", "click me"))
					.ToolTipText(LOCTEXT("ClickButton_Tooltip", "clickButton tooltip"))
				]
			]
			+ SHorizontalBox::Slot()
			.Padding(1.0f)
			.HAlign(HAlign_Fill)
			[
				SNew(SEditableTextBox)
				.Text(this, &SStandardSlateWidget::GetText)
				.OnTextChanged(this, &SStandardSlateWidget::OnTextChanged)
			]
		]
	]; 

}

#undef LOCTEXT_NAMESPACE

END_SLATE_FUNCTION_BUILD_OPTIMIZATION
           
// StandardHUD.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/HUD.h"
#include "StandardSlateWidget.h"

#include "StandardHUD.generated.h"


UCLASS()
class ANDROIDPROJECT1_API AStandardHUD : public AHUD
{
	GENERATED_BODY()
	
public:
	TSharedPtr<SStandardSlateWidget> MyUIWidget;

	void BeginPlay();
};
           
// StandardHUD.cpp

#include "StandardHUD.h"
#include "StandardSlateWidget.h"
#include "Widgets/SWeakWidget.h" 

#include "Runtime/Engine/Classes/Engine/Engine.h" 


void AStandardHUD::BeginPlay()
{
	MyUIWidget = SNew(SStandardSlateWidget);

	GEngine->GameViewport->AddViewportWidgetContent(
		SNew(SWeakWidget)
		.PossiblyNullContent(MyUIWidget.ToSharedRef())
	);

	MyUIWidget->SetVisibility(EVisibility::Visible);
}
           

其中SLATE_BEGIN_ARGS、SLATE_ARGUMENT、SLATE_END_ARGS等,是在“Epic Games\UE_4.18\Engine\Source\Runtime\SlateCore\Public\Widgets\DeclarativeSyntaxSupport.h”中定义的:

#define SLATE_BEGIN_ARGS( WidgetType ) \
	public: \
	struct FArguments : public TSlateBaseNamedArgs<WidgetType> \
	{ \
		typedef FArguments WidgetArgsType; \
		FORCENOINLINE FArguments()


#define SLATE_ARGUMENT( ArgType, ArgName ) \
		ArgType _##ArgName; \
		WidgetArgsType& ArgName( ArgType InArg ) \
		{ \
			_##ArgName = InArg; \
			return this->Me(); \
		}


#define SLATE_END_ARGS() \
	};
           

参考文档

Slate UI Framework

    Slate Architecture

    Details Panel Customization

    Using Slate In-Game

    Slate Overview

    Using Slate in a Project

    Slate Widget Examples

Slate, Hello

Slate, Loading Styles & Resources

Template:Slate Style Sets Part 2

Template:Slate Data Binding Part 3 

继续阅读