BlueRoseNote/03-UnrealEngine/UI/Slate学习笔记(一):Slate动态控制与其他技巧.md
2023-06-29 11:55:02 +08:00

5.4 KiB
Raw Permalink Blame History

title, date, tags, rating
title date tags rating
Slate学习笔记Slate动态控制与其他技巧 2021-02-19 9:22:10        Slate

前言

最近在写MessageBox控件想兼容UMG与c++中调用Slate。略有心得遂有此文。

动态Slate

首先Slate控件树中创建占位用的NullWidget并使用.Expose()绑定Slot指针使得可以进行后续操作。

ChildSlot
.VAlign(VAlign_Fill)
.HAlign(HAlign_Fill)
[
	SNew(SOverlay)
	+ SOverlay::Slot()
	.HAlign(HAlign_Center)
	.VAlign(VAlign_Center)
	.Expose(UseMenuSlot) // Expose it to a pointer so we can change the widget at runtime
	[
		SNullWidget::NullWidget
	]
];

之后就可以通过函数对Slot进行操作了下面演示如何动态添加或者删除Button

UseMenuSlot->AttachWidget(
	InText.Get().IsEmpty() ?
	SNullWidget::NullWidget 
	:
	SNew(SButton)
	.VAlign(VAlign_Center)
	.HAlign(HAlign_Center)
	[
		SNew(STextBlock)
	]
);

支持Expose()的容器

常用的: SHorizontalBox SVerticalBox SOverlay

其他还有若干也支持的

设置指定长度的Widget

有的时候需要让控件保持指定的大小使用SBox的WidthOverride与HeightOverride即可。其他的控件都不支持这2个属性。

ChildSlot
[
    SNew(SBox)
    .WidthOverride(256)
    .HeightOverride(100)
    [
        SNew(SButton)
    ]
];  

指定大小控件的UMG与Slate兼容问题

UMG的根节点是一个CanvasPanel(UCanvasPanelSlot)。我认为直接给控件加一个SBox来控制大小的方式不太好。这会使得在UMG中的调整大小变得麻烦。所以我的方法是使用c++调用Slate控件时在外面再套一层SConstraintCanvas。

UCanvasPanelSlot本质上是SConstraintCanvas。UMG编辑器中显示的Size实际上是Offset。所以想要指定大小就需要设置Offset的Right与Bottom。

CurrentWidget = SNew(SConstraintCanvas)
	+ SConstraintCanvas::Slot()
	.Anchors(0.5)
	.Alignment(FVector2D(0.5,0.5))
	.Offset(FMargin(0,0,500,400))
	[
		SNew(SCustomWidget)
	];

GetGameInstance()->GetGameViewportClient()->AddViewportWidgetContent(CurrentWidget.ToSharedRef());

c++获取UMG控件

UPROPERTY(Meta = (BindWidget)) //直接获取蓝图中的按钮1
UButton* ButtonOne;		
bool UFWAffectWidget::Initialize()
{
	if (!Super::Initialize()) return false;
	//方法1
	RootPanel = Cast<UCanvasPanel>(GetRootWidget());	//获取根控件
	if (RootPanel) 
	{
		BGImage = Cast<UImage>(RootPanel->GetChildAt(0));	//下标1的BGImage控件
	}
	//方法2
	UButton* ButtonTwo = (UButton*)GetWidgetFromName(TEXT("ButtonTwo"));

	//绑定按钮事件方法1
	ButtonOne->OnClicked.__Internal_AddDynamic(this,&UFWAffectWidget::ButtonOneEvent,FName("ButtonOneEvent"));

	//绑定事件方法2委托FScriptDelegate
	FScriptDelegate ButTwoDel;
	ButTwoDel.BindUFunction(this, "ButtonTwoEvent");
	ButtonTwo->OnReleased.Add(ButTwoDel);

	return true;
}

参考文章:https://blog.csdn.net/weixin_44200074/article/details/109100521

从UMG控件中获取Slate

TSharedRef<SWidget> UWidget::TakeWidget()

反射

遍历UProperty

for(TFiledIterator<UProperty> It(/*UClass**/)It;++It)
{
     UProperty *newProperty=It;
}

根据名称寻找UProperty

UProperty *foundProperty = FindField<UProperty>(/*UClass**/,TEXT("PropertyName"));

Get/Set UProperty

//根据PropertyPath获取属性值
FCachedPropertyPath PropertyPath(FString(TEXT("PropertyName")));
T Value;
ProperthPathHelpers::GetPropertyValue(Object,PropertyPath,Value);
//有获取就有设置
ProperthPathHelpers::SetPropertyValue(Object,PropertyPath,Value);
//还可以获取成String
FString PropertyValueStr;
ProperthPathHelpers::GetPropertyValueAsString(Object,PropertyPath,PropertyValueStr);
//同样,反向也可以
ProperthPathHelpers::SetPropertyValueFromString(Object,PropertyPath,PropertyValueStr);
//实际上我们平时在UE引擎中复制粘贴属性值就是将属性值获取为String以及从String这只属性值的整个过程。

引用文章:https://zhuanlan.zhihu.com/p/121006155 更多反射技巧:https://bebylon.dev/ue4guide/engine-programming/uobject-reflection/uobject-reflection/

SCompoundWidget、SPanel、SLeafWidget的区别

SCompoundWidget

SCompoundWidget对应于UMG中的“WidgetBlueprint控件蓝图用来作为控件容器。当我们在C++类向导中创建Slate类时创建的就是SCompoundWidget。 可以通过成员ChildSlot结合重载的[]操作符往控件里面添加其他控件

void SStandardSlateWidget::Construct(const FArguments& InArgs)
{	
	ChildSlot
	[
		SNew(STextBlock)
		.Font(FSlateFontInfo("Veranda", 100))
		.Text(NSLOCTEXT("HelloSlate", "HelloSlateText", "Hello, Slate!"))
	];
}

SPanel

即为SPanel子布局的属性包括Padding、Size、Horizontal Align、Vertical Align。 使用Slot添加子控件可以使用“+ Slot()”也可以调用AddSlot函数还是以教程1中的SStandardSlateWidget为例

void SStandardSlateWidget::Construct(const FArguments& InArgs)
{	
	ChildSlot
	[
		SAssignNew(VerticalBoxPtr, SVerticalBox)

		+ SVerticalBox::Slot()
		.Padding(1.0)
		.FillHeight(0.3f)
		.HAlign(HAlign_Fill)
		.VAlign(VAlign_Top)
		[
			SNew(SButton)
		]

		+ SVerticalBox::Slot()
		.FillHeight(0.5f)
		.HAlign(HAlign_Center)
		[
			SNew(SButton)
		]
	];

	VerticalBoxPtr->AddSlot()
		.FillHeight(0.2f)
		[
			SNew(SButton)
		];
}

SLeafWidget

叶子控件故名思意该控件不能添加子控件。常用的为STextBlock与SImage。