Unreal Slate框架随笔

小项 备注
时间 2019 年 12 月 26 日
修改时间 2020 年 3 月 22 日、2020年4月11日
城市 北京市房山区
天气
心情 凑合

UE4 的 编辑器都是建立在 Slate整个框架下,包括UE4 用于Runtime游戏的 UMG 这套这是基于Slate系统的。

Slate用户界面系统为开发者提供了 引擎源码 和 编辑器Editor 的直接访问权(开发者工具——Widget Reflecor)

0. Slate控件(S前缀的类)继承关系【SlateCore模块】

至于为什么是S开头的类,戳下面官方的链接:

https://docs.unrealengine.com/en-US/Programming/Introduction/index.html

继承关系.png

下面我们把注意力放在 FSlot类型上

(1)SCompoundWidget

SCompoundWidget 中含有一个Slot,意味着他可以添加一个 children widget

SCompoundWidget.png

(2)SLeafWidget

SLeafWidget 中没有Slot成员,也就是不含widget

SLeafWidget.png

(3)Spanel

Spanel 中可以含有多个 widget,这个没本身没有加 Slot 结构,但是 继承于他的继承类,会添加自己的 Slot结构,例如 Soverlay、SBoxPanel派生类

(3.1)Soverlay
SOverlay.png
(3.2)SBoxPanel
SBoxPanel.png
(3.2.1)SVerticalBox
SVerticalBox.png
(3.2.2)SHorizontalBox
SHorizontalBox.png

关于FSlot 的作用,在其基类中可以看出,它重载了操作符 [ ],所以我们可以 使用下面这种写法,其添加 childrenwidhet,而控件的父子关系是依托Slot实现的。Slate除了底层的渲染功能实现之外,定义了一套自己的语法,目的就是定义 UI 的层级结构和布局—也就是Slot。

ChildSlot
    [
        SNew(...)
    ]
TSlotBase.png

每一个 slot 可以存放一个widget,有的控件只有一个 slot,所以它只有一个孩子,有的控件有多个孩子,就有一个 slotArray对应,而他的排列就跟重写 SWidget基类的 OnArrangeChildren纯虚函数有关了。

多个Slot.png

1. 控件参数声明

(1)声明

Slate 声明式语法使得开发者可以直接构建用户界面,而不需要添加中间层进行处理。提供了一套 完整的宏 来简化声明及创建控件的过程。
宏 SLATE_BEGIN_ARGS宏 SLATE_END_ARGS 之间的声明参数。常用的参数类型有 SLATE_ATTRIBUTE(属性)、SLATE_EVENT(事件)、SLATE_ARGUMENT(参数)、SLATE_NAMED_SLOT(插槽) 和 SLATE_DEFAULT_SLOT

  • 例如:SLATE_ATTRIBUTE(属性)
    声明格式:SLATE_ATTRIBUTE(变量类型,变量名)*

  • 例如:SLATE_EVENT(事件)
    声明格式:SLATE_EVENT(变量类型,变量名)*
    注意:这里的变量类型为 UE4 的委托类型

  • 实例

DECLARE_DELEGATE_OneParam(FMyEvent, FString);

class EXSLATEWIDGET_API SMyCompoundWidget : public SCompoundWidget
{
public:
        SLATE_BEGIN_ARGS( SSubMenuButton )
            : _ShouldAppearHovered( false )
            {
 
            }
          
            SLATE_ATTRIBUTE( bool, ShouldAppearHovered )

            SLATE_ATTRIBUTE( FString, Label )
          
            SLATE_EVENT( FOnClicked, OnClicked )
         
            SLATE_NAMED_SLOT( FArguments, FSimpleSlot, Content )

            SLATE_EVENT(FMyEvent, MyEvent)       
        SLATE_END_ARGS()
};

(2)初始化

按上面用相应的宏声明之后,实际上参数名变为"_" + "宏里面的变量名",如上面 “ShouldAppearHovered ” 参数名为“_ShouldAppearHovered ”. SCompoundWidget的参数初始化和C++类差不多,如同下面:

SLATE_BEGIN_ARGS(SSubMenuButton )
{
    _ShouldAppearHovered = false ;
}

SLATE_BEGIN_ARGS(SSubMenuButton ):
        _ShouldAppearHovered ( false )
    {
 
    }

而在 上述的实例中采用了第二种初始化的方式。

2. 构建对象

通过 宏 声明的参数 与 类成员变量 之间的转移(参数 与 变量的区别)

在构建 Slate 对象的时候,传入的参数,并不是直接通过 上面我们通过宏去定义的那些参数去直接执行的,上面定义的那些参数 仅仅是为了 方便传递,所以还需要在 定义类的 成员变量(或委托变量)
上面实例中的类,重新定义为:

以 Label 这个声明参数为例,在类中增加了 这个声明参数 对应的 成员变量

DECLARE_DELEGATE_OneParam(FMyEvent, FString);

class EXSLATEWIDGET_API SMyCompoundWidget : public SCompoundWidget
{
public:
        SLATE_BEGIN_ARGS( SSubMenuButton )
            : _ShouldAppearHovered( false )
            {
 
            }
          
            SLATE_ATTRIBUTE( bool, ShouldAppearHovered )

            SLATE_ATTRIBUTE( FString, Label )
          
            SLATE_EVENT( FOnClicked, OnClicked )
         
            SLATE_NAMED_SLOT( FArguments, FSimpleSlot, Content )

            SLATE_EVENT(FMyEvent, MyEvent)       
        SLATE_END_ARGS()

public:
        void Construct(const FArguments& InArgs);

private:
        FString Label ;

};

/////////////////////////////////////////////////////////
void SMyCompoundWidget::Construct(const FArguments& InArgs)
{
         
        Label = InArgs._Label ;
        /*
        ChildSlot
        [
            // Populate the widget
        ];
        */

}

实际构建的代码写法

ContextualEditingWidget->AddSlot()
.Padding( 2.0f )
[
    SNew( SDetailSection )
    .SectionName("StaticMeshSection")
    .SectionTitle( LOCTEXT("StaticMeshSection", "Static Mesh").ToString() )
    .Content()
    [
        SNew( SVerticalBox )
        + SVerticalBox::Slot()
        .Padding( 3.0f, 1.0f )
        [
            SNew( SHorizontalBox )
            + SHorizontalBox::Slot()
            .Padding( 2.0f )
            [
                SNew( SComboButton )
                .ButtonContent()
                [
                    SNew( STextBlock )
                    .Text( LOCTEXT("BlockingVolumeMenu", "Create Blocking Volume") ) 
                    .Font( FontInfo )
                ]
                .MenuContent()
                [
                    BlockingVolumeBuilder.MakeWidget()
                ]
            ]
        ]

    ]
];

看 一下 的定义,就知道这些写法,以及 Construct 函数中 FArguments 参数是怎么回事了 :

宏的定义.png

这些写法 就是在对属性 赋值,并且这些声明的变量都会存在 FArguments 结构下面,
void Construct(const FArgument& InArgs);
在初始化函数可以使用到 SNew 时候传来的参数。

对于想了解 SNew 背后的逻辑的朋友,可以看下面的链接:

https://www.yuanmas.com/info/rxzKZA9ORe.html

(1)风格

在构建时,代码的具体写法中,你可以创建风格,并将其应用到一个 控件的各个部分上,这使得用户界面上迭代处理组件的外观、共享及重用风格变得更加容易。

在UE4中,主要的风格被定义在一下两个源文件中:

  • Engine \ Source \ Runtime \ SlateCore \ Public \ Styling \ CoreStyle.h
  • Engine \ Source \ Editor \ EditorStyle \ Private \ SlateEditorStyle.cpp
// Tool bar
{
    Set( "ToolBar.Background", FSlateBoxBrush( TEXT("Common/GroupBorder"), FMargin(4.0f/16.0f) ) );

    Set( "ToolBarButton.Normal", FSlateNoResource() );      // Note: Intentionally transparent background
    Set( "ToolBarButton.Pressed", FSlateBoxBrush( TEXT("Old/MenuItemButton_Pressed"), 4.0f/32.0f ) );
    Set( "ToolBarButton.Hovered", FSlateBoxBrush( TEXT("Old/MenuItemButton_Hovered"), 4.0f/32.0f ) );

    // Tool bar buttons are sometimes toggle buttons, so they need styles for "checked" state
    Set( "ToolBarButton.Checked", FSlateBoxBrush( TEXT("Old/MenuItemButton_Pressed"),  4.0f/32.0f, FLinearColor( 0.3f, 0.3f, 0.3f ) ) );
    Set( "ToolBarButton.Checked_Hovered", FSlateBoxBrush( TEXT("Old/MenuItemButton_Hovered"),  4.0f/32.0f ) );
    Set( "ToolBarButton.Checked_Pressed", FSlateBoxBrush( TEXT("Old/MenuItemButton_Pressed"),  4.0f/32.0f, FLinearColor( 0.5f, 0.5f, 0.5f ) ) );

    // Tool bar button label font
    Set( "ToolBarButton.LabelFont", FSlateFontInfo( TEXT("Roboto-Regular"), 8 ) );
}

构建的代码写法改为

SNew( SBorder )
.BorderImage( FEditorStyle::GetBrush( "ToolBar.Background" ) )
.Content()
[
    SNew(SHorizontalBox)

    // Compile button (faked to look like a multibox button)
    +SHorizontalBox::Slot()
    [
        SNew(SButton)
        .Style(TEXT("ToolBarButton"))
        .OnClicked( InKismet2.ToSharedRef(), &FKismet::Compile_OnClicked )
        .IsEnabled( InKismet2.ToSharedRef(), &FKismet::InEditingMode )
        .Content()
        [
            SNew(SVerticalBox)
            +SVerticalBox::Slot()
            .Padding( 1.0f )
            .HAlign(HAlign_Center)
            [
                SNew(SImage)
                .Image(this, &SBlueprintEditorToolbar::GetStatusImage)
                .ToolTipText(this, &SBlueprintEditorToolbar::GetStatusTooltip)
            ]
            +SVerticalBox::Slot()
            .Padding( 1.0f )
            .HAlign(HAlign_Center)
            [
                SNew(STextBlock)
                .Text(LOCTEXT("CompileButton", "Compile"))
                .Font( FEditorStyle::GetFontStyle( FName( "ToolBarButton.LabelFont" ) ) )
                .ToolTipText(LOCTEXT("CompileButton_Tooltip", "Recompile the blueprint"))
            ]
        ]
    ]
]

参考文章
https://docs.unrealengine.com/zh-CN/Programming/Slate/index.html
https://docs.unrealengine.com/zh-CN/Engine/UMG/index.html
https://blog.csdn.net/qq_29523119/article/details/98475938
https://blog.csdn.net/pizi0475/article/details/50471207
https://zhuanlan.zhihu.com/p/56127773

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,692评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,482评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,995评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,223评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,245评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,208评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,091评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,929评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,346评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,570评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,739评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,437评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,037评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,677评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,833评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,760评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,647评论 2 354

推荐阅读更多精彩内容