UE4 slateUI slot

void Construct( const FArguments& Args )
    {
        SetCanTick(false);

        this->ChildSlot
            [
                SNew(SVerticalBox)
                + SVerticalBox::Slot()
                .Padding( FMargin( 0.0f, 0.0f, 2.0f, 0.0f ) )
                [
                    FSlateApplicationBase::Get().MakeImage(
                        FSlateApplicationBase::Get().GetAppIcon(),
                        Args._IconColorAndOpacity,
                        EVisibility::HitTestInvisible
                    )
                ]
            ];
    }

slate代码这样写的,一开始学感觉很奇怪

其实这是为了减少代码而设计的.

首先这个widget继承自SCompoundWidget,这个可以有子控件,SCompoundWidget继承自SWidget,这个SWidget是基础的控件,它不可以有子控件

SCompoundWidget里面有成员 ChildSlot ,是这样定义的 FSimpleSlot ChildSlot;  这个是子控件容器

/** A slot that support alignment of content and padding */
class SLATECORE_API FSimpleSlot : public TSupportsOneChildMixin<FSimpleSlot>, public TSupportsContentAlignmentMixin<FSimpleSlot>, public TSupportsContentPaddingMixin<FSimpleSlot>
{
public:
    FSimpleSlot(SWidget* InParent)
    : TSupportsOneChildMixin<FSimpleSlot>(InParent)
    , TSupportsContentAlignmentMixin<FSimpleSlot>(HAlign_Fill, VAlign_Fill)
    {
    }
};



下面是TSupportsOneChildMixin定义

/**
 * Widgets that will only have one child can return an instance of FOneChild.
 */
template <typename MixedIntoType>
class TSupportsOneChildMixin : public FChildren, public TSlotBase<MixedIntoType>
{
public:
    TSupportsOneChildMixin(SWidget* InOwner)
        : FChildren(InOwner)
        , TSlotBase<MixedIntoType>()
    {
        this->RawParentPtr = InOwner;
    }

    virtual int32 Num() const override { return 1; }

    virtual TSharedRef<SWidget> GetChildAt( int32 ChildIndex ) override
    {
        check(ChildIndex == 0);
        return FSlotBase::GetWidget();
    }

    virtual TSharedRef<const SWidget> GetChildAt( int32 ChildIndex ) const override
    {
        check(ChildIndex == 0);
        return FSlotBase::GetWidget();
    }

private:
    virtual const FSlotBase& GetSlotAt(int32 ChildIndex) const override { check(ChildIndex == 0); return *this; }
};

而TSlotBase有重写[]  方法

template<typename SlotType>
class TSlotBase : public FSlotBase
{
public:

    TSlotBase()
    : FSlotBase()
    {}

    TSlotBase( const TSharedRef<SWidget>& InWidget )
    : FSlotBase( InWidget )
    {}

    SlotType& operator[]( const TSharedRef<SWidget>& InChildWidget )
    {
        this->AttachWidget(InChildWidget);
        return (SlotType&)(*this);
    }

    SlotType& Expose( SlotType*& OutVarToInit )
    {
        OutVarToInit = (SlotType*)this;
        return (SlotType&)(*this);
    }
};

所以有上面那个方括号里面写代码的内容,意思就是方括号里面的widget 加到子控件数组里

 

 

template <typename MixedIntoType>
class TSupportsContentAlignmentMixin
{
public:
    TSupportsContentAlignmentMixin(const EHorizontalAlignment InHAlign, const EVerticalAlignment InVAlign)
    : HAlignment( InHAlign )
    , VAlignment( InVAlign )
    {
        
    }

    MixedIntoType& HAlign( EHorizontalAlignment InHAlignment )
    {
        HAlignment = InHAlignment;
        return *(static_cast<MixedIntoType*>(this));
    }

    MixedIntoType& VAlign( EVerticalAlignment InVAlignment )
    {
        VAlignment = InVAlignment;
        return *(static_cast<MixedIntoType*>(this));
    }
    
    EHorizontalAlignment HAlignment;
    EVerticalAlignment VAlignment;
};

template <typename MixedIntoType>
class TSupportsContentPaddingMixin
{
public:
    MixedIntoType& Padding( const TAttribute<FMargin> InPadding )
    {
        SlotPadding = InPadding;
        return *(static_cast<MixedIntoType*>(this));
    }

    MixedIntoType& Padding( float Uniform )
    {
        SlotPadding = FMargin(Uniform);
        return *(static_cast<MixedIntoType*>(this));
    }

    MixedIntoType& Padding( float Horizontal, float Vertical )
    {
        SlotPadding = FMargin(Horizontal, Vertical);
        return *(static_cast<MixedIntoType*>(this));
    }

    MixedIntoType& Padding( float Left, float Top, float Right, float Bottom )
    {
        SlotPadding = FMargin(Left, Top, Right, Bottom);
        return *(static_cast<MixedIntoType*>(this));
    }

    TAttribute< FMargin > SlotPadding;
};

而slot继承自TSupportsContentAlignmentMixinTSupportsContentPaddingMixin, 所以具备  .HAlign  .VAlign 和 .Padding功能

 

DeclarativeSyntaxSupport.h 这个文件里面包含了一些宏定义

/**
 * Use this macro between SLATE_BEGIN_ARGS and SLATE_END_ARGS
 * in order to add support for slots.
 */
#define SLATE_SUPPORTS_SLOT( SlotType ) \
        TArray< SlotType* > Slots; \
        WidgetArgsType& operator + (SlotType& SlotToAdd) \
        { \
            Slots.Add( &SlotToAdd ); \
            return *this; \
        }

而widget里面调用了这个

SLATE_BEGIN_ARGS( SHorizontalBox )
    {
        _Visibility = EVisibility::SelfHitTestInvisible;
    }

        SLATE_SUPPORTS_SLOT(SHorizontalBox::FSlot)

    SLATE_END_ARGS()

如果Widget只有一个Slot,可以直接用[ ]来添加widget

#define SLATE_DEFAULT_SLOT( DeclarationType, SlotName ) \
        SLATE_NAMED_SLOT(DeclarationType, SlotName) ; \
        DeclarationType & operator[]( const TSharedRef<SWidget> InChild ) \
        { \
            _##SlotName.Widget = InChild; \
            return *this; \
        }

 

 

这里定义了一个slots数组,  添加了 + 的重载符,就是可以向这个数组里面加 slot,

而类里面有一个这个静态函数,调用的时候这样SVerticalBox::Slot() 表示new 一个slot

static FSlot& Slot()
    {
        return *(new FSlot());
    }

 

然后你就可以这样写了  + SVerticalBox::Slot()

 

 

抄个简单的,后面自己的ui也改成这个方式

 

#include<stdio.h>

#include<vector>
enum EHorizontalAlignment
{
    HAlign_Fill ,
    HAlign_Left,
    HAlign_Center,
    HAlign_Right,
};

enum EVerticalAlignment
{
    VAlign_Fill,
    VAlign_Top,
    VAlign_Center,
    VAlign_Bottom,
};

struct FMargin
{
    float Left;
    float Top;
    float Right;
    float Bottom;

    FMargin()
        : Left(0.0f)
        , Top(0.0f)
        , Right(0.0f)
        , Bottom(0.0f)
    { }

    
    FMargin(float UniformMargin)
        : Left(UniformMargin)
        , Top(UniformMargin)
        , Right(UniformMargin)
        , Bottom(UniformMargin)
    { }

    
    FMargin(float Horizontal, float Vertical)
        : Left(Horizontal)
        , Top(Vertical)
        , Right(Horizontal)
        , Bottom(Vertical)
    { }

    FMargin(float InLeft, float InTop, float InRight, float InBottom)
        : Left(InLeft)
        , Top(InTop)
        , Right(InRight)
        , Bottom(InBottom)
    { }
};



template<typename MixedIntoType>
class TSupportsContentAlignmentMixin
{
public:
    TSupportsContentAlignmentMixin(const EHorizontalAlignment InHAlign, const EVerticalAlignment InVAlign)
        : HAlignment(InHAlign)
        , VAlignment(InVAlign)
    {

    }

    MixedIntoType& HAlign(EHorizontalAlignment InHAlignment)
    {
        HAlignment = InHAlignment;
        return *(static_cast<MixedIntoType*>(this));
    }

    MixedIntoType& VAlign(EVerticalAlignment InVAlignment)
    {
        VAlignment = InVAlignment;
        return *(static_cast<MixedIntoType*>(this));
    }

    EHorizontalAlignment HAlignment;
    EVerticalAlignment VAlignment;
};


template <typename MixedIntoType>
class TSupportsContentPaddingMixin
{
public:
    MixedIntoType& Padding(const FMargin InPadding)
    {
        SlotPadding = InPadding;
        return *(static_cast<MixedIntoType*>(this));
    }

    MixedIntoType& Padding(float Uniform)
    {
        SlotPadding = FMargin(Uniform);
        return *(static_cast<MixedIntoType*>(this));
    }

    MixedIntoType& Padding(float Horizontal, float Vertical)
    {
        SlotPadding = FMargin(Horizontal, Vertical);
        return *(static_cast<MixedIntoType*>(this));
    }

    MixedIntoType& Padding(float Left, float Top, float Right, float Bottom)
    {
        SlotPadding = FMargin(Left, Top, Right, Bottom);
        return *(static_cast<MixedIntoType*>(this));
    }

    FMargin SlotPadding;
};

class Widget;

class FSlotBase
{
public:
    FSlotBase(){}

    FSlotBase(Widget& InWidget)
    {
        m_Widget = &InWidget;
    }

    void AttachWidget(Widget& InWidget)
    {

        m_Widget = &InWidget;
    }


    const Widget* GetWidget() const
    {
        return m_Widget;
    }
private:
    // non-copyable
    FSlotBase& operator=(const FSlotBase&);
    FSlotBase(const FSlotBase&);

    Widget* m_Widget;

};



template<typename SlotType>
class TSlotBase : public FSlotBase
{
public:

    TSlotBase()
        : FSlotBase()
    {}

    TSlotBase(Widget* InWidget)
        : FSlotBase(InWidget)
    {}

    SlotType& operator[](Widget& InChildWidget)
    {
        this->AttachWidget(InChildWidget);
        return (SlotType&)(*this);
    }

    SlotType& Expose(SlotType*& OutVarToInit)
    {
        OutVarToInit = (SlotType*)this;
        return (SlotType&)(*this);
    }
};





class Widget
{
public:

    class FSlot :public TSlotBase<FSlot>,public TSupportsContentAlignmentMixin<FSlot>,public TSupportsContentPaddingMixin<FSlot>
    {
    public:
        FSlot()
        :TSupportsContentAlignmentMixin<FSlot>(HAlign_Fill, VAlign_Fill)
        {}
    };

    
    Widget& operator + (FSlot& SlotToAdd)
    { 
        Slots.push_back(&SlotToAdd); 
        return *this; 
    }

    static FSlot& Slot()
    {
        return *(new FSlot());
    }


    FSlot& AddSlot()
    {
        FSlot* NewSlot = new FSlot();
        Slots.push_back(NewSlot);
        return *NewSlot;
    }

public:
    

    std::vector<FSlot*>  Slots;
};


template<typename WidgetType>
struct TDecl
{
    void Make()
    {
        m_Widget = new WidgetType();
    }



    WidgetType* m_Widget;
};


Widget SNew()
{
    Widget* temp = new Widget();

    return *temp;
}
  


int main()
{
    Widget twidget ;

    twidget.AddSlot()
        [

            SNew()
            + Widget::Slot()
            .Padding(1)
            .HAlign(HAlign_Center)
            .VAlign(VAlign_Bottom)
            [
                SNew()

            ]
            + Widget::Slot()
            .Padding(1)
            .HAlign(HAlign_Fill)
            .VAlign(VAlign_Fill)
            [
                SNew()
            ]
        ];

    twidget+ Widget::Slot()
        [

            SNew()
        ];

    return 0;
}

 

posted on 2022-01-18 13:15  c_dragon  阅读(321)  评论(0编辑  收藏  举报

导航