原创文章,转载请注明出处。
点击观看上一篇《UE4 Slate一 开篇》
点击观看下一篇《UE4 Slate三 SlateUI代码讲解》
虚幻引擎 SlateUI介绍
1>前言
我们基于编辑器插件EditorStandaloneWindow来作为载体制作我们的SlateUI。
Engine Version:4.25.4
文章内的插件代码下载链接
解压后放到Plugins目录下
2>为什么要用UMG去理解我们的Slate?
做之前我是先根据我想完成的样子做了一个UMG,然后再用Slate实现成我这个UMG的样子。
1>因为Slate并不可视化,需要我们在代码里面手动一行行的敲(链式编程)
2>写Slate的时候可以对照UMG的参数,将参数给到我们的Slate上
3>对照着写,方便我们记录写到了什么位置了。(链式编程)代码实在是有点变态(不友好),一长串往下的都是。
3>Slate的书写格式(链式编程)
优点:
1>效率比UMG要高,因为UMG封装的就是Slate
缺点:
1>不能断点调试,断点无法命中链式内部
2>编写界面制作麻烦且不易维护
4>编码前第一步, 创建我们的Editor Standalone Window插件
Plugins文件夹下的test5_EditorStandlonWindow就是我们新建的插件, 注意我们这个插件是Editor模式下才会被加载的,当然我们可以把Slate的代码移植到我们的GamePlay里面,新弄个模块,这样就能参与我们的GamePlay部分的逻辑了。
创建完后启动编辑器会多出如下图的一个图标
5>编码前第二步, 创建我们的参考UMG
下面我们将用Slate来实现出上面的UMG样子来
6>编码,直接贴出代码,下一篇文章中再对代码详细介绍
6.1>SlateUI代码,纯UI代码,没有往插件面板上加
6.1.1>头文件SlateMain.h
SlateMain.h这个文件是创建的UI,但是还没有被加到插件的视口上
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "SlateCore.h"
#include "Widgets/SCompoundWidget.h"
#include "Components/SlateWrapperTypes.h"
#include "Animation/CurveSequence.h"
#include "SlateMainWidgetStyle.h"
//Slot概念很重要, 插槽就是说我们在他下面可以添加多少个子控件,下面有三个我们写Slate会经常继承的类
//SCompoundWidget有一个插槽, 固定一个, SButton, SBox
//SPanel: 多个插槽 比如SVerticalBox, SHorizontalBox
//SLeafWidget:没有插槽, 比如STextBlock
class SMyAnimationSlate;
//这个类的作用就是去用Slate代码实现一次这个UMG(WidgetBlueprint'/Game/Blogs_Slate/ReferUMGBP.ReferUMGBP')
class SMainSlate : public SCompoundWidget /*public SUserWidget*/
{
public:
//SLATE_BEGIN_ARGS+SLATE_END_ARGS 其实是一个结构体, 内部写的东西都相当于写在了一个结构体里面
SLATE_BEGIN_ARGS(SMainSlate)
{
}
SLATE_END_ARGS()
//外部执行SNew或者SAssignNew时候会调用Construct()
void Construct(const FArguments& InArgs);
protected:
//SButton的事件绑定
FReply OnFirstSButton_OnClicked();
void OnFirstSButton_OnPressed();
void OnFirstSButton_OnReleased();
void OnFirstSButton_OnHovered();
void OnFirstSButton_OnUnhovered();
//SChechBox的事件绑定
template<int32 T>
void MyOnCheckStateChanged(ECheckBoxState emState)
{
if (CheckBoxArray.IsValidIndex(T))
{
for (int32 i = 0; i < CheckBoxArray.Num(); i++)
{
if (i == T)
{
if (CheckBoxArray[i].IsValid() || CheckBoxArray[i].Get())
{
CheckBoxArray[i]->SetIsChecked(emState);
}
}
else
{
if (CheckBoxArray[i].IsValid() || CheckBoxArray[i].Get())
{
CheckBoxArray[i]->SetIsChecked(ECheckBoxState::Unchecked);
}
}
}
}
}
private:
//最外层的层, 就是我们默认创建UMG带的层
TSharedPtr<class SConstraintCanvas> CanvasPanel_0;
//存放SCheckBox的数组, 选中后可维护唯一选中
TArray<TSharedPtr<class SCheckBox>> CheckBoxArray;
//左侧层
TSharedPtr<class SScrollBox> MyScrollBoxLeft;
//右侧层
TSharedPtr<class SScrollBox> MyScrollBoxRight;
//自定义的样式
const struct FMainWidgetStyle *MyCustomWidgetStyle;
};
//Slate动画演示类
class SMyAnimationSlate : public SCompoundWidget /*public SUserWidget*/
{
public:
//SLATE_BEGIN_ARGS+SLATE_END_ARGS 其实是一个结构体, 内部写的东西都相当于写在了一个结构体里面
SLATE_BEGIN_ARGS(SMyAnimationSlate)
{
_Visibility = EVisibility::SelfHitTestInvisible;
}
//外部Slot里面的都是作为这个Slate里面的ChildSlot出现
SLATE_DEFAULT_SLOT(FArguments, OutSlots)
SLATE_END_ARGS()
//外部执行SNew或者SAssignNew时候会调用Construct()
void Construct(const FArguments& InArgs);
//鼠标进入
virtual void OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
//鼠标离开
virtual void OnMouseLeave(const FPointerEvent& MouseEvent) override;
//颜色变化
FLinearColor SlateColorChanged();
private:
//Slate动画对象
FCurveSequence MySlateCurveSequence;
};
6.1.2>cpp文件SlateMain.cpp
SlateMain.cpp这个文件是创建的UI,但是还没有被加到插件的视口上
#include "SlateMain.h"
#include "Widgets/Layout/SConstraintCanvas.h"
#include "Widgets/Layout/SScrollBox.h"
#include <test5_EditorStandlonWindowStyle.h>
#define LOCTEXT_NAMESPACE "SlateMain"
static int32 nDynamicAddNum = 0;
void SMainSlate::Construct(const FArguments& InArgs)
{
//计数器
nDynamicAddNum = 0;
//初始化checkbox数组, 默认给3个值
CheckBoxArray.SetNum(3);
//获取自定义样式
MyCustomWidgetStyle = &Ftest5_EditorStandlonWindowStyle::Get().GetWidgetStyle<FMainWidgetStyle>(TEXT("MyCustomWidgetStyleBP"));
//链式编程 维护很麻烦...
ChildSlot
[
SAssignNew(CanvasPanel_0, SConstraintCanvas)
+ SConstraintCanvas::Slot()
.Anchors(0.f) //对应UMG这个文本控件上的Anchors属性,拷贝过来即可
.Offset(FMargin(600, 0.f, 100, 100)) //这个可能会迷惑, 第一个参数在这是PositionX, 第二个参数在这是PositionY, 第三个参数在这是SizeX, 第四个参数在这是SizeY.找不到设置坐标的同学注意看这里
.Alignment(FVector2D(0.f, 0.f)) //同样的, 对应Alignment是个FVector2D
.AutoSize(false) //对应AutoSize
.ZOrder(0)
[
SNew(SImage)
.Image(&MyCustomWidgetStyle->TemplateImage)
.ColorAndOpacity(FSlateColor(MyCustomWidgetStyle->TemplateColor))
]
//对应UMG(WidgetBlueprint'/Game/Blogs_Slate/ReferUMGBP.ReferUMGBP')中的<Mesh合并界面>文本
+ SConstraintCanvas::Slot()
.Anchors(0.f) //对应UMG这个文本控件上的Anchors属性,拷贝过来即可
.Offset(FMargin(20.0, 12.f, 600, 72)) //这个可能会迷惑, 第一个参数在这是PositionX, 第二个参数在这是PositionY, 第三个参数在这是SizeX, 第四个参数在这是SizeY.找不到设置坐标的同学注意看这里
.Alignment(FVector2D(0.f, 0.f)) //同样的, 对应Alignment是个FVector2D
.AutoSize(false) //对应AutoSize
.ZOrder(0)
[
SNew(STextBlock)
.Text(LOCTEXT("SMainSlate_TextBlock1", "Mesh合并界面"))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 53))
.ColorAndOpacity(FSlateColor(FLinearColor(1, 0, 0.361307, 1)))
]
//对应UMG(WidgetBlueprint'/Game/Blogs_Slate/ReferUMGBP.ReferUMGBP')中的<Level中的模型列表>文本
+SConstraintCanvas::Slot()
.Anchors(0.f)
.Offset(FMargin(132, 128, 350.0, 40)) //这个可能会迷惑, 第一个参数在这是PositionX, 第二个参数在这是PositionY, 第三个参数在这是SizeX, 第四个参数在这是SizeY.找不到设置坐标的同学注意看这里
.Alignment(FVector2D(0.f, 0.f)) //同样的, 对应Alignment是个FVector2D
.AutoSize(false) //对应AutoSize
.ZOrder(0)
[
SNew(STextBlock)
.Text(LOCTEXT("SMainSlate_TextBlock2", "Level中的模型列表"))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 24))
.ColorAndOpacity(FSlateColor(FLinearColor(1, 1, 1, 1)))
]
//对应左侧的ScrollBox
+ SConstraintCanvas::Slot()
.Anchors(0.f)
.Offset(FMargin(132, 180.0, 369, 625)) //这个可能会迷惑, 第一个参数在这是PositionX, 第二个参数在这是PositionY, 第三个参数在这是SizeX, 第四个参数在这是SizeY.找不到设置坐标的同学注意看这里
.Alignment(FVector2D(0.f, 0.f)) //同样的, 对应Alignment是个FVector2D
.AutoSize(false) //对应AutoSize
.ZOrder(0)
[
SAssignNew(MyScrollBoxLeft, SScrollBox)
.Orientation(Orient_Vertical)
.ScrollBarAlwaysVisible(true)
+ SScrollBox::Slot()
.Padding(0.f)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
//链式编程里面不能写for, 所以我就new5个吧。。。
SNew(STextBlock)
.Text(LOCTEXT("SMainSlate_SVerticalBox_TextBlock1", "场景中模型_1"))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 24))
]
+ SScrollBox::Slot()
.Padding(0.f)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
//链式编程里面不能写for, 所以我就new5个吧。。。
SNew(STextBlock)
.Text(LOCTEXT("SMainSlate_SVerticalBox_TextBlock2", "场景中模型_2"))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 24))
]
+ SScrollBox::Slot()
.Padding(0.f)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
//链式编程里面不能写for, 所以我就new5个吧。。。
SNew(STextBlock)
.Text(LOCTEXT("SMainSlate_SVerticalBox_TextBlock3", "场景中模型_3"))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 24))
]
+ SScrollBox::Slot()
.Padding(0.f)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
//链式编程里面不能写for, 所以我就new5个吧。。。
SNew(STextBlock)
.Text(LOCTEXT("SMainSlate_SVerticalBox_TextBlock4", "场景中模型_4"))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 24))
]
+ SScrollBox::Slot()
.Padding(0.f)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
//链式编程里面不能写for, 所以我就new5个吧。。。
SNew(STextBlock)
.Text(LOCTEXT("SMainSlate_SVerticalBox_TextBlock5", "场景中模型_5"))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 24))
]
]
//对应UMG(WidgetBlueprint'/Game/Blogs_Slate/ReferUMGBP.ReferUMGBP')中的<Level中的模型列表>文本
+ SConstraintCanvas::Slot()
.Anchors(0.f)
.Offset(FMargin(764.0, 128, 350.0, 40)) //这个可能会迷惑, 第一个参数在这是PositionX, 第二个参数在这是PositionY, 第三个参数在这是SizeX, 第四个参数在这是SizeY.找不到设置坐标的同学注意看这里
.Alignment(FVector2D(0.f, 0.f)) //同样的, 对应Alignment是个FVector2D
.AutoSize(false) //对应AutoSize
.ZOrder(0)
[
SNew(STextBlock)
.Text(LOCTEXT("SMainSlate_TextBlock3", "预览->按材质合并之后的"))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 24))
.ColorAndOpacity(FSlateColor(FLinearColor(1, 1, 1, 1)))
]
//对应中间的ScrollBox
+ SConstraintCanvas::Slot()
.Anchors(0.f)
.Offset(FMargin(764, 180.0, 370.0, 625)) //这个可能会迷惑, 第一个参数在这是PositionX, 第二个参数在这是PositionY, 第三个参数在这是SizeX, 第四个参数在这是SizeY.找不到设置坐标的同学注意看这里
.Alignment(FVector2D(0.f, 0.f)) //同样的, 对应Alignment是个FVector2D
.AutoSize(false) //对应AutoSize
.ZOrder(0)
[
SAssignNew(MyScrollBoxRight, SScrollBox)
.Orientation(Orient_Vertical)
.ScrollBarAlwaysVisible(true)
+ SScrollBox::Slot()
.Padding(0.f)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
//链式编程里面不能写for, 所以我就new5个吧。。。
SNew(STextBlock)
.Text(LOCTEXT("SMainSlate_SVerticalBox2_TextBlock1", "预览->按材质合并之后的模型_1"))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 24))
]
+ SScrollBox::Slot()
.Padding(0.f)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
//链式编程里面不能写for, 所以我就new5个吧。。。
SNew(STextBlock)
.Text(LOCTEXT("SMainSlate_SVerticalBox2_TextBlock2", "预览->按材质合并之后的模型_2"))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 24))
]
+ SScrollBox::Slot()
.Padding(0.f)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
//链式编程里面不能写for, 所以我就new5个吧。。。
SNew(STextBlock)
.Text(LOCTEXT("SMainSlate_SVerticalBox2_TextBlock3", "预览->按材质合并之后的模型_3"))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 24))
]
+ SScrollBox::Slot()
.Padding(0.f)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
//链式编程里面不能写for, 所以我就new5个吧。。。
SNew(STextBlock)
.Text(LOCTEXT("SMainSlate_SVerticalBox2_TextBlock4", "预览->按材质合并之后的模型_4"))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 24))
]
+ SScrollBox::Slot()
.Padding(0.f)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
//链式编程里面不能写for, 所以我就new5个吧。。。
SNew(STextBlock)
.Text(LOCTEXT("SMainSlate_SVerticalBox2_TextBlock5", "预览->按材质合并之后的模型_5"))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 24))
]
]
//对应UMG(WidgetBlueprint'/Game/Blogs_Slate/ReferUMGBP.ReferUMGBP')中的<Button_458>
+SConstraintCanvas::Slot()
.Anchors(0.f)
.Offset(FMargin(584.0, 468.0, 100.0, 40)) //这个可能会迷惑, 第一个参数在这是PositionX, 第二个参数在这是PositionY, 第三个参数在这是SizeX, 第四个参数在这是SizeY.找不到设置坐标的同学注意看这里
.Alignment(FVector2D(0.f, 0.f)) //同样的, 对应Alignment是个FVector2D
.AutoSize(false) //对应AutoSize
.ZOrder(0)
[
SNew(SButton)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
.ContentPadding(0.f)
.OnClicked(this, &SMainSlate::OnFirstSButton_OnClicked) //事件绑定的技巧, 转到定义, 看那边的代理是怎么定义的, 把参数和返回值拿过来定义一个函数即可
.OnPressed(this, &SMainSlate::OnFirstSButton_OnPressed)
.OnReleased(this, &SMainSlate::OnFirstSButton_OnReleased)
.OnHovered(this, &SMainSlate::OnFirstSButton_OnHovered)
.OnUnhovered(this, &SMainSlate::OnFirstSButton_OnUnhovered)
[
SNew(STextBlock)
.Text(LOCTEXT("SMainSlate_Button_Text1", "---->"))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 24))
]
]
//对应UMG(WidgetBlueprint'/Game/Blogs_Slate/ReferUMGBP.ReferUMGBP')中的<Button_Merge>
+ SConstraintCanvas::Slot()
.Anchors(0.f)
.Offset(FMargin(1520.0, 888.0, 225.0, 90)) //这个可能会迷惑, 第一个参数在这是PositionX, 第二个参数在这是PositionY, 第三个参数在这是SizeX, 第四个参数在这是SizeY.找不到设置坐标的同学注意看这里
.Alignment(FVector2D(0.f, 0.f)) //同样的, 对应Alignment是个FVector2D
.AutoSize(false) //对应AutoSize
.ZOrder(0)
[
SNew(SButton)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
.ContentPadding(0.f)
.OnClicked(this, &SMainSlate::OnFirstSButton_OnClicked) //事件绑定的技巧, 转到定义, 看那边的代理是怎么定义的, 把参数和返回值拿过来定义一个函数即可
.OnPressed(this, &SMainSlate::OnFirstSButton_OnPressed)
.OnReleased(this, &SMainSlate::OnFirstSButton_OnReleased)
.OnHovered(this, &SMainSlate::OnFirstSButton_OnHovered)
.OnUnhovered(this, &SMainSlate::OnFirstSButton_OnUnhovered)
[
SNew(STextBlock)
.Text(LOCTEXT("SMainSlate_Button_Text2", "一键合并"))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 30))
]
]
//对应UMG(WidgetBlueprint'/Game/Blogs_Slate/ReferUMGBP.ReferUMGBP')中的<CheckBox_1>
+ SConstraintCanvas::Slot()
.Anchors(0.f)
.Offset(FMargin(1260.0, 172.0, 600.0, 40.0)) //这个可能会迷惑, 第一个参数在这是PositionX, 第二个参数在这是PositionY, 第三个参数在这是SizeX, 第四个参数在这是SizeY.找不到设置坐标的同学注意看这里
.Alignment(FVector2D(0.f, 0.f)) //同样的, 对应Alignment是个FVector2D
.AutoSize(false) //对应AutoSize
.ZOrder(0)
[
SAssignNew(CheckBoxArray[0], SCheckBox)
.IsChecked(false)
.IsEnabled(true)
.OnCheckStateChanged(this, &SMainSlate::MyOnCheckStateChanged<0>)
[
SNew(STextBlock)
.Text(LOCTEXT("SMainSlate_checkbox_Text1", "按材质合并成SingleMesh"))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 24))
]
]
//对应UMG(WidgetBlueprint'/Game/Blogs_Slate/ReferUMGBP.ReferUMGBP')中的<CheckBox_2>
+ SConstraintCanvas::Slot()
.Anchors(0.f)
.Offset(FMargin(1260.0, 264.0, 600.0, 40.0)) //这个可能会迷惑, 第一个参数在这是PositionX, 第二个参数在这是PositionY, 第三个参数在这是SizeX, 第四个参数在这是SizeY.找不到设置坐标的同学注意看这里
.Alignment(FVector2D(0.f, 0.f)) //同样的, 对应Alignment是个FVector2D
.AutoSize(false) //对应AutoSize
.ZOrder(0)
[
SAssignNew(CheckBoxArray[1], SCheckBox)
.IsChecked(false)
.IsEnabled(true)
.OnCheckStateChanged(this, &SMainSlate::MyOnCheckStateChanged<1>)
[
SNew(STextBlock)
.Text(LOCTEXT("SMainSlate_checkbox_Text2", "按材质合并成InstanceMesh"))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 24))
]
]
//对应UMG(WidgetBlueprint'/Game/Blogs_Slate/ReferUMGBP.ReferUMGBP')中的<CheckBox_3>
+ SConstraintCanvas::Slot()
.Anchors(0.f)
.Offset(FMargin(1260.0, 360.0, 600.0, 40.0)) //这个可能会迷惑, 第一个参数在这是PositionX, 第二个参数在这是PositionY, 第三个参数在这是SizeX, 第四个参数在这是SizeY.找不到设置坐标的同学注意看这里
.Alignment(FVector2D(0.f, 0.f)) //同样的, 对应Alignment是个FVector2D
.AutoSize(false) //对应AutoSize
.ZOrder(0)
[
SAssignNew(CheckBoxArray[2], SCheckBox)
.IsChecked(false)
.IsEnabled(true)
.OnCheckStateChanged(this, &SMainSlate::MyOnCheckStateChanged<2>)
[
SNew(STextBlock)
.Text(LOCTEXT("SMainSlate_checkbox_Text2", "按材质合并成HeighInstanceMesh"))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 24))
]
]
//测试动画的
+ SConstraintCanvas::Slot()
.Anchors(0.f)
.Offset(FMargin(100, 600, 200, 200)) //这个可能会迷惑, 第一个参数在这是PositionX, 第二个参数在这是PositionY, 第三个参数在这是SizeX, 第四个参数在这是SizeY.找不到设置坐标的同学注意看这里
.Alignment(FVector2D(0.f, 0.f)) //同样的, 对应Alignment是个FVector2D
.AutoSize(false) //对应AutoSize
.ZOrder(0)
[
SNew(SMyAnimationSlate)
[
SNew(SButton)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
.ContentPadding(0.f)
.OnClicked(this, &SMainSlate::OnFirstSButton_OnClicked) //事件绑定的技巧, 转到定义, 看那边的代理是怎么定义的, 把参数和返回值拿过来定义一个函数即可
.OnPressed(this, &SMainSlate::OnFirstSButton_OnPressed)
.OnReleased(this, &SMainSlate::OnFirstSButton_OnReleased)
.OnHovered(this, &SMainSlate::OnFirstSButton_OnHovered)
.OnUnhovered(this, &SMainSlate::OnFirstSButton_OnUnhovered)
[
SNew(STextBlock)
.Text(LOCTEXT("SMainSlate_ButtonSlateAnimation_Text3333", "测试Slate动画"))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 24))
]
]
]
];
}
FReply SMainSlate::OnFirstSButton_OnClicked()
{
GEngine->AddOnScreenDebugMessage(-1, 1.f, FColor::Green, TEXT("OnFirstSButton_OnClicked"));
++nDynamicAddNum;
FString s2 = TEXT("new add") + FString::FromInt(nDynamicAddNum);
MyScrollBoxLeft->AddSlot()
[
SNew(STextBlock)
.Text(FText::FromString(s2))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 24))
.ColorAndOpacity(FSlateColor(FLinearColor(1, 0, 1, 1)))
];
MyScrollBoxRight->AddSlot()
[
SNew(STextBlock)
.Text(FText::FromString(s2))
.Font(FCoreStyle::GetDefaultFontStyle("Roboto", 24))
.ColorAndOpacity(FSlateColor(FLinearColor(1, 1, 0, 1)))
];
return FReply::Handled();
}
void SMainSlate::OnFirstSButton_OnPressed()
{
//UE_LOG(LogTemp, Warning, TEXT("OnFirstSButton_OnPressed"));
GEngine->AddOnScreenDebugMessage(-1, 1.f, FColor::Green, TEXT("OnFirstSButton_OnPressed"));
}
void SMainSlate::OnFirstSButton_OnReleased()
{
GEngine->AddOnScreenDebugMessage(-1, 1.f, FColor::Green, TEXT("OnFirstSButton_OnReleased"));
}
void SMainSlate::OnFirstSButton_OnHovered()
{
GEngine->AddOnScreenDebugMessage(-1, 1.f, FColor::Green, TEXT("OnFirstSButton_OnHovered"));
}
void SMainSlate::OnFirstSButton_OnUnhovered()
{
GEngine->AddOnScreenDebugMessage(-1, 1.f, FColor::Green, TEXT("OnFirstSButton_OnUnhovered"));
}
void SMyAnimationSlate::Construct(const FArguments& InArgs)
{
MySlateCurveSequence = FCurveSequence(0.f, 1.f);
ColorAndOpacity = TAttribute<FLinearColor>::Create(TAttribute<FLinearColor>::FGetter::CreateSP(this, &SMyAnimationSlate::SlateColorChanged));
ChildSlot
[
InArgs._OutSlots.Widget
];
}
void SMyAnimationSlate::OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if (!MySlateCurveSequence.IsAtEnd())
{
if (MySlateCurveSequence.IsInReverse() && MySlateCurveSequence.IsPlaying())
{
MySlateCurveSequence.Reverse();
}
else if (!MySlateCurveSequence.IsPlaying())
{
MySlateCurveSequence.Play(this->AsShared());
}
}
}
void SMyAnimationSlate::OnMouseLeave(const FPointerEvent& MouseEvent)
{
if (!MySlateCurveSequence.IsAtStart())
{
if (!MySlateCurveSequence.IsInReverse() && MySlateCurveSequence.IsPlaying())
{
MySlateCurveSequence.Reverse();
}
else if (!MySlateCurveSequence.IsPlaying())
{
MySlateCurveSequence.PlayReverse(this->AsShared());
}
}
}
FLinearColor SMyAnimationSlate::SlateColorChanged()
{
return FLinearColor(1, 1, 1, 1 - MySlateCurveSequence.GetLerp());
}
#undef LOCTEXT_NAMESPACE
6.2>将上面创建的SlateUI添加到插件面板上
因为我们是基于UE4 Plugin创建了一个Editor Standlone Window,
在这个插件代码中(test5_EditorStandlonWindow.cpp)中的OnSpawnPluginTab()方法中,
就是创建Slate的部分,所以我们在这个位置写就好了。
下面我们在test5_EditorStandlonWindow.cpp 中的OnSpawnPluginTab()方法中SNew/SAssignNew我们在上面新建好的SMainSlate
然后打开我们编辑器就能看到效果了,下一篇对本篇写的Slate的代码做一些介绍
TSharedRef<SDockTab> Ftest5_EditorStandlonWindowModule::OnSpawnPluginTab(const FSpawnTabArgs& SpawnTabArgs)
{
FText WidgetText = FText::Format(
LOCTEXT("WindowWidgetText", "Add code to {0} in {1} to override this window's contents"),
FText::FromString(TEXT("Ftest5_EditorStandlonWindowModule::OnSpawnPluginTab")),
FText::FromString(TEXT("test5_EditorStandlonWindow.cpp"))
);
//第一种方式
MyMainSlate = SNew(SMainSlate);
return SNew(SDockTab)
[
MyMainSlate->AsShared()
];
//第二种方式
/*SAssignNew(MyMainSlate, SMainSlate);
return SNew(SDockTab)
[
MyMainSlate->AsShared()
];*/
//第三种方式
/*return SNew(SDockTab)
[
SNew(SMainSlate)
];*/
//第四种方式
/*return SNew(SDockTab)
[
SAssignNew(MyMainSlate, SMainSlate)
];*/
//原来的代码注释掉了
//.TabRole(ETabRole::NomadTab)
//[
// // Put your tab content here!
// SNew(SBox)
// .HAlign(HAlign_Center)
// .VAlign(VAlign_Center)
// [
// SNew(STextBlock)
// .Text(WidgetText)
// ]
//];
}
写了这么多效果是什么样子的呢?
7>SlateUI效果
点击观看上一篇《UE4 Slate一 开篇》
点击观看下一篇《UE4 Slate三 SlateUI代码讲解》
谢谢,创作不易,大侠请留步… 动起可爱的双手,来个赞再走呗 <( ̄︶ ̄)>