199 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			199 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
---
 | 
						||
title: Slate学习笔记(一):Slate动态控制与其他技巧
 | 
						||
date: 2021-02-19 9:22:10       
 | 
						||
tags: Slate
 | 
						||
rating: ⭐️ 
 | 
						||
---
 | 
						||
## 前言 
 | 
						||
最近在写MessageBox控件,想兼容UMG与c++中调用Slate。略有心得,遂有此文。
 | 
						||
 | 
						||
## 动态Slate
 | 
						||
首先Slate控件树中创建占位用的NullWidget并使用.Expose()绑定Slot指针,使得可以进行后续操作。
 | 
						||
```c++
 | 
						||
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:
 | 
						||
```c++
 | 
						||
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个属性。
 | 
						||
```c++
 | 
						||
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。
 | 
						||
```c++
 | 
						||
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控件
 | 
						||
```c++
 | 
						||
UPROPERTY(Meta = (BindWidget)) //直接获取蓝图中的按钮1
 | 
						||
UButton* ButtonOne;		
 | 
						||
```
 | 
						||
```c++
 | 
						||
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
 | 
						||
```c++
 | 
						||
TSharedRef<SWidget> UWidget::TakeWidget()
 | 
						||
```
 | 
						||
 | 
						||
## 反射
 | 
						||
### 遍历UProperty
 | 
						||
```c++
 | 
						||
for(TFiledIterator<UProperty> It(/*UClass**/);It;++It)
 | 
						||
{
 | 
						||
     UProperty *newProperty=It;
 | 
						||
}
 | 
						||
```
 | 
						||
### 根据名称寻找UProperty
 | 
						||
```c++
 | 
						||
UProperty *foundProperty = FindField<UProperty>(/*UClass**/,TEXT("PropertyName"));
 | 
						||
```
 | 
						||
### Get/Set UProperty
 | 
						||
```c++
 | 
						||
//根据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结合重载的[]操作符往控件里面添加其他控件
 | 
						||
```c++
 | 
						||
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为例
 | 
						||
```c++
 | 
						||
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。 |