UE4 Slate的语法初步分析

我们用一个具体的Slate的例子来分析语法.

首先我们新建个EditorStandaloneWindow类型的插件,命名为PlantMonster,在PlantMonster.cpp中有一个TSharedRef FPlantMonsterModule::OnSpawnPluginTab(const FSpawnTabArgs& SpawnTabArgs)的方法.方法中使用了 SNew(SDockTab) 宏. 准备工作结束,下面我们一步一步开始分析.

  1. 首先我们对 SDockTab.h 中出现的宏来分析.
    ① SLATE_BEGIN_ARGS 宏替换后如下
    `
/**
 * Widget authors can use SLATE_BEGIN_ARGS and SLATE_END_ARS to add support
 * for widget construction via SNew and SAssignNew.
 * e.g.
 * 
 *    SLATE_BEGIN_ARGS( SMyWidget )
 *         , _PreferredWidth( 150.0f )
 *         , _ForegroundColor( FLinearColor::White )
 *         {}
 *
 *         SLATE_ATTRIBUTE(float, PreferredWidth)
 *         SLATE_ATTRIBUTE(FSlateColor, ForegroundColor)
 *    SLATE_END_ARGS()
 */
#define SLATE_BEGIN_ARGS( SDockTab) \
	public: \
	struct FArguments : public TSlateBaseNamedArgs<SDockTab> \
	{ \
		typedef FArguments FArguments; \
		FORCENOINLINE FArguments()`

这个宏,在 SDockTab 类中,声明了一个嵌套类(资料:https://blog.csdn.net/Poo_Chai/article/details/91596538 https://blog.csdn.net/liyuanbhu/article/details/43897979 )FArguments,
这个 FArguments 类,继承模板类 TSlateBaseNamedArgs,具体类型后TSlateBaseNamedArgs定义如下

/** Base class for named arguments. Provides settings necessary for all widgets. */
template<typename SDockTab>
struct TSlateBaseNamedArgs
{
	TSlateBaseNamedArgs()
	: _ToolTipText()
	, _ToolTip()
	, _Cursor( TOptional<EMouseCursor::Type>() )
	, _IsEnabled( true )
	, _Visibility( EVisibility::Visible )
	, _RenderOpacity(1.0f)
	, _ForceVolatile( false )
	, _Clipping( EWidgetClipping::Inherit )
	, _FlowDirectionPreference( EFlowDirectionPreference::Inherit )
	, _RenderTransform( )
	, _RenderTransformPivot( FVector2D::ZeroVector )
	, _AccessibleParams()
	, _AccessibleText()
	{
	}

	/** Used by the named argument pattern as a safe way to 'return *this' for call-chaining purposes. */
	SDockTab::FArguments& Me()
	{
		return *(static_cast<SDockTab::FArguments*>(this));
	}

	/** Add metadata to this widget. */
	SDockTab::FArguments& AddMetaData(TSharedRef<ISlateMetaData> InMetaData)
	{
		MetaData.Add(InMetaData);
		return Me();
	}

	/** Add metadata to this widget - convenience method - 1 argument */
	template<typename MetaDataType, typename Arg0Type>
	SDockTab::FArguments& AddMetaData(Arg0Type InArg0)
	{
		MetaData.Add(MakeShared<MetaDataType>(InArg0));
		return Me();
	}

	/** Add metadata to this widget - convenience method - 2 arguments */
	template<typename MetaDataType, typename Arg0Type, typename Arg1Type>
	SDockTab::FArguments& AddMetaData(Arg0Type InArg0, Arg1Type InArg1)
	{
		MetaData.Add(MakeShared<MetaDataType>(InArg0, InArg1));
		return Me();
	}

	SLATE_ATTRIBUTE( FText, ToolTipText )
	SLATE_ARGUMENT( TSharedPtr<IToolTip>, ToolTip )
	SLATE_ATTRIBUTE( TOptional<EMouseCursor::Type>, Cursor )
	SLATE_ATTRIBUTE( bool, IsEnabled )
	SLATE_ATTRIBUTE( EVisibility, Visibility )
	SLATE_ARGUMENT( float, RenderOpacity )
	SLATE_ARGUMENT( bool, ForceVolatile )
	SLATE_ARGUMENT( EWidgetClipping, Clipping )
	SLATE_ARGUMENT( EFlowDirectionPreference, FlowDirectionPreference)
	SLATE_ATTRIBUTE( TOptional<FSlateRenderTransform>, RenderTransform )
	SLATE_ATTRIBUTE( FVector2D, RenderTransformPivot )
	SLATE_ARGUMENT( FName, Tag )
	SLATE_ARGUMENT(TOptional<FAccessibleWidgetData>, AccessibleParams)
	SLATE_ATTRIBUTE(FText, AccessibleText)

	TArray<TSharedRef<ISlateMetaData>> MetaData;
};

下面分析 TSlateBaseNamedArgs(FArguments的父类) 类中的SLATE_ATTRIBUTE 宏 ,其中一个例子
SLATE_ATTRIBUTE( FText, ToolTipText ) 其宏替换后的结果如下:

/**
 * Use this macro to add a attribute to the declaration of your widget.
 * An attribute can be a value or a function.
 */
#define SLATE_ATTRIBUTE( FText, ToolTipText ) \
		TAttribute< FText > _ToolTipText; \
		SDockTab::FArguments& ToolTipText( const TAttribute< FText >& InAttribute ) \
		{ \
			_ToolTipText = InAttribute; \
			return this->Me(); \
		} \
	\
		/* Bind attribute with delegate to a global function
		 * NOTE: We use a template here to avoid 'typename' issues when hosting attributes inside templated classes */ \
		template< typename StaticFuncPtr > \
		SDockTab::FArguments& ToolTipText_Static( StaticFuncPtr InFunc )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateStatic( InFunc ) ); \
			return this->Me(); \
		} \
		template< typename Var1Type > \
		SDockTab::FArguments& ToolTipText_Static( typename TAttribute< FText >::FGetter::template TStaticDelegate_OneVar< Var1Type >::FFuncPtr InFunc, Var1Type Var1 )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateStatic( InFunc, Var1 ) ); \
			return this->Me(); \
		} \
		template< typename Var1Type, typename Var2Type > \
		SDockTab::FArguments& ToolTipText_Static( typename TAttribute< FText >::FGetter::template TStaticDelegate_TwoVars< Var1Type, Var2Type >::FFuncPtr InFunc, Var1Type Var1, Var2Type Var2 )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateStatic( InFunc, Var1, Var2 ) ); \
			return this->Me(); \
		} \
		template< typename Var1Type, typename Var2Type, typename Var3Type > \
		SDockTab::FArguments& ToolTipText_Static( typename TAttribute< FText >::FGetter::template TStaticDelegate_ThreeVars< Var1Type, Var2Type, Var3Type >::FFuncPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3 )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateStatic( InFunc, Var1, Var2, Var3 ) ); \
			return this->Me(); \
		} \
		template< typename Var1Type, typename Var2Type, typename Var3Type, typename Var4Type > \
		SDockTab::FArguments& ToolTipText_Static( typename TAttribute< FText >::FGetter::template TStaticDelegate_FourVars< Var1Type, Var2Type, Var3Type, Var4Type >::FFuncPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3, Var4Type Var4 )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateStatic( InFunc, Var1, Var2, Var3, Var4 ) ); \
			return this->Me(); \
		} \
	\
		/* Bind attribute with delegate to a lambda
		 * technically this works for any functor types, but lambdas are the primary use case */ \
		SDockTab::FArguments& ToolTipText_Lambda(TFunction< FText(void) >&& InFunctor) \
		{ \
			_ToolTipText = TAttribute< FText >::Create(Forward<TFunction< FText(void) >>(InFunctor)); \
			return this->Me(); \
		} \
	\
		/* Bind attribute with delegate to a raw C++ class method */ \
		template< class UserClass >	\
		SDockTab::FArguments& ToolTipText_Raw( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TRawMethodDelegate_Const< UserClass >::FMethodPtr InFunc )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateRaw( InUserObject, InFunc ) ); \
			return this->Me(); \
		} \
		template< class UserClass, typename Var1Type >	\
		SDockTab::FArguments& ToolTipText_Raw( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TRawMethodDelegate_OneVar_Const< UserClass, Var1Type  >::FMethodPtr InFunc, Var1Type Var1 )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateRaw( InUserObject, InFunc, Var1 ) ); \
			return this->Me(); \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type >	\
		SDockTab::FArguments& ToolTipText_Raw( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TRawMethodDelegate_TwoVars_Const< UserClass, Var1Type, Var2Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2 )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateRaw( InUserObject, InFunc, Var1, Var2 ) ); \
			return this->Me(); \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type >	\
		SDockTab::FArguments& ToolTipText_Raw( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TRawMethodDelegate_ThreeVars_Const< UserClass, Var1Type, Var2Type, Var3Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3 )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateRaw( InUserObject, InFunc, Var1, Var2, Var3 ) ); \
			return this->Me(); \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type, typename Var4Type >	\
		SDockTab::FArguments& ToolTipText_Raw( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TRawMethodDelegate_FourVars_Const< UserClass, Var1Type, Var2Type, Var3Type, Var4Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3, Var4Type Var4 )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateRaw( InUserObject, InFunc, Var1, Var2, Var3, Var4 ) ); \
			return this->Me(); \
		} \
	\
		/* Bind attribute with delegate to a shared pointer-based class method.  Slate mostly uses shared pointers so we use an overload for this type of binding. */ \
		template< class UserClass >	\
		SDockTab::FArguments& ToolTipText( TSharedRef< UserClass > InUserObjectRef, typename TAttribute< FText >::FGetter::template TSPMethodDelegate_Const< UserClass >::FMethodPtr InFunc )	\
		{ \
			_ToolTipText = TAttribute< FText >( InUserObjectRef, InFunc ); \
			return this->Me(); \
		} \
		template< class UserClass, typename Var1Type >	\
		SDockTab::FArguments& ToolTipText( TSharedRef< UserClass > InUserObjectRef, typename TAttribute< FText >::FGetter::template TSPMethodDelegate_OneVar_Const< UserClass, Var1Type >::FMethodPtr InFunc, Var1Type Var1 )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateSP( InUserObjectRef, InFunc, Var1 ) ); \
			return this->Me(); \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type >	\
		SDockTab::FArguments& ToolTipText( TSharedRef< UserClass > InUserObjectRef, typename TAttribute< FText >::FGetter::template TSPMethodDelegate_TwoVars_Const< UserClass, Var1Type, Var2Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2 )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateSP( InUserObjectRef, InFunc, Var1, Var2 ) ); \
			return this->Me(); \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type >	\
		SDockTab::FArguments& ToolTipText( TSharedRef< UserClass > InUserObjectRef, typename TAttribute< FText >::FGetter::template TSPMethodDelegate_ThreeVars_Const< UserClass, Var1Type, Var2Type, Var3Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3 )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateSP( InUserObjectRef, InFunc, Var1, Var2, Var3 ) ); \
			return this->Me(); \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type, typename Var4Type >	\
		SDockTab::FArguments& ToolTipText( TSharedRef< UserClass > InUserObjectRef, typename TAttribute< FText >::FGetter::template TSPMethodDelegate_FourVars_Const< UserClass, Var1Type, Var2Type, Var3Type, Var4Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3, Var4Type Var4 )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateSP( InUserObjectRef, InFunc, Var1, Var2, Var3, Var4 ) ); \
			return this->Me(); \
		} \
	\
		/* Bind attribute with delegate to a shared pointer-based class method.  Slate mostly uses shared pointers so we use an overload for this type of binding. */ \
		template< class UserClass >	\
		SDockTab::FArguments& ToolTipText( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TSPMethodDelegate_Const< UserClass >::FMethodPtr InFunc )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateSP( InUserObject, InFunc ) ); \
			return this->Me(); \
		} \
		template< class UserClass, typename Var1Type >	\
		SDockTab::FArguments& ToolTipText( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TSPMethodDelegate_OneVar_Const< UserClass, Var1Type >::FMethodPtr InFunc, Var1Type Var1 )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateSP( InUserObject, InFunc, Var1 ) ); \
			return this->Me(); \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type >	\
		SDockTab::FArguments& ToolTipText( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TSPMethodDelegate_TwoVars_Const< UserClass, Var1Type, Var2Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2 )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateSP( InUserObject, InFunc, Var1, Var2 ) ); \
			return this->Me(); \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type >	\
		SDockTab::FArguments& ToolTipText( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TSPMethodDelegate_ThreeVars_Const< UserClass, Var1Type, Var2Type, Var3Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3 )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateSP( InUserObject, InFunc, Var1, Var2, Var3 ) ); \
			return this->Me(); \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type, typename Var4Type >	\
		SDockTab::FArguments& ToolTipText( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TSPMethodDelegate_FourVars_Const< UserClass, Var1Type, Var2Type, Var3Type, Var4Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3, Var4Type Var4 )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateSP( InUserObject, InFunc, Var1, Var2, Var3, Var4 ) ); \
			return this->Me(); \
		} \
	\
		/* Bind attribute with delegate to a UObject-based class method */ \
		template< class UserClass >	\
		SDockTab::FArguments& ToolTipText_UObject( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TUObjectMethodDelegate_Const< UserClass >::FMethodPtr InFunc )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateUObject( InUserObject, InFunc ) ); \
			return this->Me(); \
		} \
		template< class UserClass, typename Var1Type >	\
		SDockTab::FArguments& ToolTipText_UObject( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TUObjectMethodDelegate_OneVar_Const< UserClass, Var1Type >::FMethodPtr InFunc, Var1Type Var1 )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateUObject( InUserObject, InFunc, Var1 ) ); \
			return this->Me(); \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type  >	\
		SDockTab::FArguments& ToolTipText_UObject( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TUObjectMethodDelegate_TwoVars_Const< UserClass, Var1Type, Var2Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2 )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateUObject( InUserObject, InFunc, Var1, Var2 ) ); \
			return this->Me(); \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type >	\
		SDockTab::FArguments& ToolTipText_UObject( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TUObjectMethodDelegate_ThreeVars_Const< UserClass, Var1Type, Var2Type, Var3Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3 )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateUObject( InUserObject, InFunc, Var1, Var2, Var3 ) ); \
			return this->Me(); \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type, typename Var4Type >	\
		SDockTab::FArguments& ToolTipText_UObject( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TUObjectMethodDelegate_FourVars_Const< UserClass, Var1Type, Var2Type, Var3Type, Var4Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3, Var4Type Var4 )	\
		{ \
			_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateUObject( InUserObject, InFunc, Var1, Var2, Var3, Var4 ) ); \
			return this->Me(); \
		}

所以 SLATE_ATTRIBUTE 宏为 TSlateBaseNamedArgs(FArguments的父类) 类定义了TAttribute< FText >类型的成员变量_ToolTipText以及不同参数类型成员函数ToolTipText_Static

另外要说明一点的是 :在 TAttribute(Attribute.h) 模板类中有 使用了这样一个宏

	/**
	 * Attribute 'getter' delegate
	 *
	 * ObjectType GetValue() const
	 *
	 * @return  The attribute's value
	 */
	DECLARE_DELEGATE_RetVal( ObjectType, FGetter );

它的定义如下

#define DECLARE_DELEGATE_RetVal( ReturnValueType, DelegateName ) FUNC_DECLARE_DELEGATE( DelegateName, ReturnValueType )

宏 FUNC_DECLARE_DELEGATE 的定义如下

/** Declare the user's delegate object */
// NOTE: The last parameter is variadic and is used as the 'template args' for this delegate's classes (__VA_ARGS__)
#define FUNC_DECLARE_DELEGATE( DelegateName, ... ) \
	typedef TBaseDelegate<__VA_ARGS__> DelegateName;

所以 DECLARE_DELEGATE_RetVal( ObjectType, FGetter );宏替换之后就是

typedef TBaseDelegate<ObjectType> FGetter ;

因此 FGetter 就是TBaseDelegate – (TBaseDelegate 的父类为 FDelegateBase),换句话说 FGetter 就是 SDockTab 类中的 FArguments 类中的 TAttribute 类中的 类型为TBaseDelegate 的类名.
有关Delegate的具体实现过程,之后再分析

好,下面继续回到SLATE_ATTRIBUTE宏,在宏 SLATE_ATTRIBUTE( FText, ToolTipText ) 中实现的一个如下函数

template< typename Var1Type > \
SDockTab::FArguments& ToolTipText_Static( typename TAttribute< FText >::FGetter::template TStaticDelegate_OneVar< Var1Type >::FFuncPtr InFunc, Var1Type Var1 )	\
{ \
	_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateStatic( InFunc, Var1 ) ); \
	return this->Me(); \
} \

其中,TStaticDelegate_OneVar 是 TBaseDelegate 类中的内嵌类,这个TStaticDelegate_OneVar 类的父类为 TBaseStaticDelegateInstance,template TStaticDelegate_OneVar< Var1Type >::FFuncPtr InFunc 中的template表示后边跟着的是一个函数模板指针,
这个函数
SDockTab::FArguments& ToolTipText_Static( typename TAttribute< FText >::FGetter::template TStaticDelegate_OneVar< Var1Type >::FFuncPtr InFunc, Var1Type Var1 )
的功能就是给SDockTab::FArguments的 TAttribute< FText >类型的 _ToolTipText字段初始化

下面分析 SLATE_ARGUMENT 宏 SLATE_ARGUMENT( TSharedPtr, ToolTip ) 宏替换后

/**
 * Use this macro to declare a slate argument.
 * Arguments differ from attributes in that they can only be values
 */
#define SLATE_ARGUMENT( TSharedPtr<IToolTip>, ToolTip ) \
		SharedPtr<IToolTip> _ToolTip; \
		FArguments& ToolTip( SharedPtr<IToolTip> InArg ) \
		{ \
			_ToolTip = InArg; \
			return this->Me(); \
		}

这个宏的作用就是声明一个SharedPtr类型(共享指针)的字段 _ToolTip,并给出初始化方法
--------------------- 以上是对 FArguments 的父类 TSlateBaseNamedArgs中的宏分析 -----
下面对SDockTab.h中的宏分析
SLATE_DEFAULT_SLOT( FArguments, Content )的定义,宏替换后为

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

其中 SLATE_NAMED_SLOT 的定义 宏替换后如下

/**
 * Use this macro to add support for named slot properties such as Content and Header. See NamedSlotProperty for more details.
 *
 * NOTE: If you're using this within a widget class that is templated, then you might have to specify a full name for the declaration.
 *       For example: SLATE_NAMED_SLOT( typename SSuperWidget<T>::Declaration, Content )
 */
#define SLATE_NAMED_SLOT( FArguments, Content ) \
		NamedSlotProperty< FArguments > Content() \
		{ \
			return NamedSlotProperty< FArguments >( *this, _Content ); \
		} \
		TAlwaysValidWidget _Content; \

所以

宏替换之后  SLATE_DEFAULT_SLOT 如下
#define SLATE_DEFAULT_SLOT( FArguments, Content ) \
		NamedSlotProperty< FArguments > Content() \
		{ \
			return NamedSlotProperty< FArguments >( *this, _Content ); \
		} \
		TAlwaysValidWidget _Content; \
		FArguments & operator[]( const TSharedRef<SWidget> InChild ) \
		{ \
			_Content.Widget = InChild; \
			return *this; \
		}

其中 NamedSlotProperty 类的定义 具体类型替换后如下

/**
 * We want to be able to do:
 * SNew( ContainerWidget )
 * .SomeContentArea()
 * [
 *   // Child widgets go here
 * ]
 *
 * NamedSlotProperty is a helper that will be returned by SomeContentArea().
 */
template<class FArguments> 
struct NamedSlotProperty
{
	NamedSlotProperty( FArguments& InOwnerDeclaration, TAlwaysValidWidget& ContentToSet )
		: OwnerDeclaration( InOwnerDeclaration )
		, SlotContent(ContentToSet)
	{}

	FArguments & operator[]( const TSharedRef<SWidget>& InChild )
	{
		SlotContent.Widget = InChild;
		return OwnerDeclaration;
	}

	FArguments & OwnerDeclaration;
	TAlwaysValidWidget & SlotContent;
};

这个 NamedSlotProperty 类重写了操作符[],使之能够添加子widget ,这个类的字段 SlotContent 的类型为 TAlwaysValidWidget 其定义如下

/** A widget reference that is always a valid pointer; defaults to SNullWidget */
struct TAlwaysValidWidget
{
	TAlwaysValidWidget()
	: Widget(SNullWidget::NullWidget)
	{
	}

	TSharedRef<SWidget> Widget;
};

所以 SLATE_DEFAULT_SLOT( FArguments, Content ) 这个宏的作用就是在
SDockTab类中的FArguments类中定义 了一个返回值类型为 NamedSlotProperty< FArguments > 的方法 Content() , 声明了一个类型为 TAlwaysValidWidget 的字段 _Content, 重写了操作符 [] (注意NamedSlotProperty也重写了操作符[] )

下面分析宏 SLATE_EVENT( FOnTabClosedCallback, OnTabClosed ) (#define SLATE_EVENT( DelegateName, EventName )) 其宏替换后

TabClosedCallback::template TSPMethodDelegate_OneVar_Const< UserClass, Var1Type >::FMethodPtr InFunc, Var1Type Var1 )	\
		{ \
			_OnTabClosed = FOnTabClosedCallback::CreateSP( InUserObject, InFunc, Var1 ); \
			return *this; \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type >	\
		FArguments& OnTabClosed( UserClass* InUserObject, typename FOnTabClosedCallback::template TSPMethodDelegate_TwoVars< UserClass, Var1Type, Var2Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2 )	\
		{ \
			_OnTabClosed = FOnTabClosedCallback::CreateSP( InUserObject, InFunc, Var1, Var2 ); \
			return *this; \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type >	\
		FArguments& OnTabClosed( UserClass* InUserObject, typename FOnTabClosedCallback::template TSPMethodDelegate_TwoVars_Const< UserClass, Var1Type, Var2Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2 )	\
		{ \
			_OnTabClosed = FOnTabClosedCallback::CreateSP( InUserObject, InFunc, Var1, Var2 ); \
			return *this; \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type >	\
		FArguments& OnTabClosed( UserClass* InUserObject, typename FOnTabClosedCallback::template TSPMethodDelegate_ThreeVars< UserClass, Var1Type, Var2Type, Var3Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3 )	\
		{ \
			_OnTabClosed = FOnTabClosedCallback::CreateSP( InUserObject, InFunc, Var1, Var2, Var3 ); \
			return *this; \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type >	\
		FArguments& OnTabClosed( UserClass* InUserObject, typename FOnTabClosedCallback::template TSPMethodDelegate_ThreeVars_Const< UserClass, Var1Type, Var2Type, Var3Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3 )	\
		{ \
			_OnTabClosed = FOnTabClosedCallback::CreateSP( InUserObject, InFunc, Var1, Var2, Var3 ); \
			return *this; \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type, typename Var4Type >	\
		FArguments& OnTabClosed( UserClass* InUserObject, typename FOnTabClosedCallback::template TSPMethodDelegate_FourVars< UserClass, Var1Type, Var2Type, Var3Type, Var4Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3, Var4Type Var4 )	\
		{ \
			_OnTabClosed = FOnTabClosedCallback::CreateSP( InUserObject, InFunc, Var1, Var2, Var3, Var4 ); \
			return *this; \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type, typename Var4Type >	\
		FArguments& OnTabClosed( UserClass* InUserObject, typename FOnTabClosedCallback::template TSPMethodDelegate_FourVars_Const< UserClass, Var1Type, Var2Type, Var3Type, Var4Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3, Var4Type Var4 )	\
		{ \
			_OnTabClosed = FOnTabClosedCallback::CreateSP( InUserObject, InFunc, Var1, Var2, Var3, Var4 ); \
			return *this; \
		} \
		\
		/* Set event delegate to a UObject-based class method */ \
		template< class UserClass >	\
		FArguments& OnTabClosed_UObject( UserClass* InUserObject, typename FOnTabClosedCallback::template TUObjectMethodDelegate< UserClass >::FMethodPtr InFunc )	\
		{ \
			_OnTabClosed = FOnTabClosedCallback::CreateUObject( InUserObject, InFunc ); \
			return *this; \
		} \
		template< class UserClass >	\
		FArguments& OnTabClosed_UObject( UserClass* InUserObject, typename FOnTabClosedCallback::template TUObjectMethodDelegate_Const< UserClass >::FMethodPtr InFunc )	\
		{ \
			_OnTabClosed = FOnTabClosedCallback::CreateUObject( InUserObject, InFunc ); \
			return *this; \
		} \
		template< class UserClass, typename Var1Type >	\
		FArguments& OnTabClosed_UObject( UserClass* InUserObject, typename FOnTabClosedCallback::template TUObjectMethodDelegate_OneVar< UserClass, Var1Type >::FMethodPtr InFunc, Var1Type Var1 )	\
		{ \
			_OnTabClosed = FOnTabClosedCallback::CreateUObject( InUserObject, InFunc, Var1 ); \
			return *this; \
		} \
		template< class UserClass, typename Var1Type >	\
		FArguments& OnTabClosed_UObject( UserClass* InUserObject, typename FOnTabClosedCallback::template TUObjectMethodDelegate_OneVar_Const< UserClass, Var1Type >::FMethodPtr InFunc, Var1Type Var1 )	\
		{ \
			_OnTabClosed = FOnTabClosedCallback::CreateUObject( InUserObject, InFunc, Var1 ); \
			return *this; \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type >	\
		FArguments& OnTabClosed_UObject( UserClass* InUserObject, typename FOnTabClosedCallback::template TUObjectMethodDelegate_TwoVars< UserClass, Var1Type, Var2Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2 )	\
		{ \
			_OnTabClosed = FOnTabClosedCallback::CreateUObject( InUserObject, InFunc, Var1, Var2 ); \
			return *this; \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type >	\
		FArguments& OnTabClosed_UObject( UserClass* InUserObject, typename FOnTabClosedCallback::template TUObjectMethodDelegate_TwoVars_Const< UserClass, Var1Type, Var2Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2 )	\
		{ \
			_OnTabClosed = FOnTabClosedCallback::CreateUObject( InUserObject, InFunc, Var1, Var2 ); \
			return *this; \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type >	\
		FArguments& OnTabClosed_UObject( UserClass* InUserObject, typename FOnTabClosedCallback::template TUObjectMethodDelegate_ThreeVars< UserClass, Var1Type, Var2Type, Var3Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3 )	\
		{ \
			_OnTabClosed = FOnTabClosedCallback::CreateUObject( InUserObject, InFunc, Var1, Var2, Var3 ); \
			return *this; \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type >	\
		FArguments& OnTabClosed_UObject( UserClass* InUserObject, typename FOnTabClosedCallback::template TUObjectMethodDelegate_ThreeVars_Const< UserClass, Var1Type, Var2Type, Var3Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3 )	\
		{ \
			_OnTabClosed = FOnTabClosedCallback::CreateUObject( InUserObject, InFunc, Var1, Var2, Var3 ); \
			return *this; \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type, typename Var4Type >	\
		FArguments& OnTabClosed_UObject( UserClass* InUserObject, typename FOnTabClosedCallback::template TUObjectMethodDelegate_FourVars< UserClass, Var1Type, Var2Type, Var3Type, Var4Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3, Var4Type Var4 )	\
		{ \
			_OnTabClosed = FOnTabClosedCallback::CreateUObject( InUserObject, InFunc, Var1, Var2, Var3, Var4 ); \
			return *this; \
		} \
		template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type, typename Var4Type >	\
		FArguments& OnTabClosed_UObject( UserClass* InUserObject, typename FOnTabClosedCallback::template TUObjectMethodDelegate_FourVars_Const< UserClass, Var1Type, Var2Type, Var3Type, Var4Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3, Var4Type Var4 )	\
		{ \
			_OnTabClosed = FOnTabClosedCallback::CreateUObject( InUserObject, InFunc, Var1, Var2, Var3, Var4 ); \
			return *this; \
		} \
		\
		FOnTabClosedCallback _OnTabClosed; \

这个宏 SLATE_EVENT( FOnTabClosedCallback, OnTabClosed ) 的作用就是 声明了一个 FOnTabClosedCallback 类型的字段_OnTabClosed,并给出了一堆初始化它的方法,FOnTabClosedCallback 类型又是由 在SDockableTab.h中的宏 DECLARE_DELEGATE_OneParam(FOnTabClosedCallback, TSharedRef); 生成的 , 又是个Delegate,与FGetter不同的是 :用的是不同参数的TBaseDelegate模板类

最后分析 SLATE_END_ARGS()

#define SLATE_END_ARGS() \
	}; 

就是给 SLATE_BEGIN_ARGS 补全一对{}

-----------------------以上是对 SDockTab.h 中出现的宏的分析-----------------------
下面 我们回到文章的开头 ,我们说在 , 在函数 TSharedRef FPlantMonsterModule::OnSpawnPluginTab(const FSpawnTabArgs& SpawnTabArgs) 中 出现了 SNew(SDockTab) ,
我们对SNew进行分析,SNew 宏替换后为

/**
 * Slate widgets are constructed through SNew and SAssignNew.
 * e.g.
 *      
 *     TSharedRef<SButton> MyButton = SNew(SButton);
 *        or
 *     TSharedPtr<SButton> MyButton;
 *     SAssignNew( MyButton, SButton );
 *
 * Using SNew and SAssignNew ensures that widgets are populated
 */

#define SNew( SDockTab, ... ) \
	MakeTDecl<SDockTab>( "SDockTab", __FILE__, __LINE__, RequiredArgs::MakeRequiredArgs(__VA_ARGS__) ) <<= TYPENAME_OUTSIDE_TEMPLATE SDockTab::FArguments()

先说 MakeTDecl(“SDockTab”, FILE, LINE, RequiredArgs::MakeRequiredArgs(VA_ARGS)) 中的参数 RequiredArgs::MakeRequiredArgs(VA_ARGS)

在命名空间RequiredArgs中 定义并实现了不同参数的 MakeRequiredArgs 方法, 返回值也与参数的个数相应 ,SNew(SDockTab)中参数个数为0个 因此 RequiredArgs::MakeRequiredArgs(VA_ARGS) 返回的是一个 RequiredArgs::T0RequiredArgs() 对象

其中 MakeTDecl 的定义 具体类型替换后为

template<typename SDockTab, typename RequiredArgs::T0RequiredArgs>
TDecl<SDockTab, RequiredArgs::T0RequiredArgs> MakeTDecl(const ANSICHAR* InType, const ANSICHAR* InFile, int32 OnLine, RequiredArgs::T0RequiredArgs&& InRequiredArgs)
{
	return TDecl<SDockTab, RequiredArgs::T0RequiredArgs>(InType, InFile, OnLine, Forward<RequiredArgs::T0RequiredArgs>(InRequiredArgs));
}

其中 TDecl 的定义 具体类型替换后为

/**
 * Utility class used during widget instantiation.
 * Performs widget allocation and construction.
 * Ensures that debug info is set correctly.
 * Returns TSharedRef to widget.
 *
 * @see SNew
 * @see SAssignNew
 */
template<class SDockTab, typename RequiredArgs::T0RequiredArgs>
struct TDecl
{
	TDecl( const ANSICHAR* InType, const ANSICHAR* InFile, int32 OnLine, RequiredArgs::T0RequiredArgs&& InRequiredArgs )
		: _Widget( TWidgetAllocator<SDockTab, TIsDerivedFrom<SDockTab, SUserWidget>::IsDerived >::PrivateAllocateWidget() )
		, _RequiredArgs(InRequiredArgs)
	{
		_Widget->SetDebugInfo( InType, InFile, OnLine, sizeof(SDockTab) );
	}

	/**
	 * Initialize OutVarToInit with the widget that is being constructed.
	 * @see SAssignNew
	 */
	template<class ExposeAsSDockTab>
	TDecl& Expose( TSharedPtr<ExposeAsSDockTab>& OutVarToInit )
	{
		OutVarToInit = _Widget;
		return *this;
	}

	/**
	 * Initialize OutVarToInit with the widget that is being constructed.
	 * @see SAssignNew
	 */
	template<class ExposeAsSDockTab>
	TDecl& Expose( TSharedRef<ExposeAsSDockTab>& OutVarToInit )
	{
		OutVarToInit = _Widget;
		return *this;
	}

	/**
	 * Initialize a WEAK OutVarToInit with the widget that is being constructed.
	 * @see SAssignNew
	 */
	template<class ExposeAsSDockTab>
	TDecl& Expose( TWeakPtr<ExposeAsSDockTab>& OutVarToInit )
	{
		OutVarToInit = _Widget;
		return *this;
	}

	/**
	 * Complete widget construction from InArgs.
	 *
	 * @param InArgs  NamedArguments from which to construct the widget.
	 *
	 * @return A reference to the widget that we constructed.
	 */
	TSharedRef<SDockTab> operator<<=( const typename SDockTab::FArguments& InArgs ) const
	{
		//@todo UMG: This should be removed in favor of all widgets calling their superclass construct.
		_Widget->SWidgetConstruct(
			InArgs._ToolTipText,
			InArgs._ToolTip,
			InArgs._Cursor,
			InArgs._IsEnabled,
			InArgs._Visibility,
			InArgs._RenderOpacity,
			InArgs._RenderTransform,
			InArgs._RenderTransformPivot,
			InArgs._Tag,
			InArgs._ForceVolatile,
			InArgs._Clipping,
			InArgs._FlowDirectionPreference,
			InArgs._AccessibleText.IsSet() ? FAccessibleWidgetData(InArgs._AccessibleText) : InArgs._AccessibleParams,
			InArgs.MetaData );

		_RequiredArgs.CallConstruct(_Widget, InArgs);

		return _Widget;
	}

	const TSharedRef<SDockTab> _Widget;
	RequiredArgs::T0RequiredArgs& _RequiredArgs;
};

在构造函数TDecl中有这样的一个方法 TWidgetAllocator<SDockTab, TIsDerivedFrom<SDockTab, SUserWidget>::IsDerived >::PrivateAllocateWidget() 这个方法就是返回一个TSharedRef的共享指针,我们分析构造函数其中的类
模板类 TIsDerivedFrom,具体化参数后的定义为

/** Is type DerivedType inherited from SUserWidget. */
template<typename SDockTab, typename SUserWidget>
struct TIsDerivedFrom
{
	// Different size types so we can compare their sizes later.
	typedef char No[1];
	typedef char Yes[2];

	// Overloading Test() s.t. only calling it with something that is
	// a SUserWidget (or inherited from the SUserWidget) will return a Yes.
	static Yes& Test( SUserWidget* );
	static Yes& Test( const SUserWidget* );
	static No& Test( ... );

	// Makes a SDockTab ptr.
	static SDockTab* SDockTabPtr(){ return nullptr ;}

	public:
	// Test the derived type pointer. If it inherits from SUserWidget, the Test( SUserWidget* ) 
	// will be chosen. If it does not, Test( ... ) will be chosen.
	static const bool Value = sizeof(Test( SDockTabPtr() )) == sizeof(Yes);

	static const bool IsDerived = Value;
};

模板类 TWidgetAllocator,具体化参数后的定义为

/** Normal widgets are allocated directly by the TDecl. */
template<typename SDockTab, bool IsDerived>
struct TWidgetAllocator
{
	static TSharedRef<SDockTab> PrivateAllocateWidget()
	{
		return MakeShared<SDockTab>();
	}
};

由上分析 宏 SNew( SDockTab, … ) 可以看成

#define SNew( SDockTab, ... ) \
TDecl<class SDockTab, typename RequiredArgs::T0RequiredArgs>() <<= TYPENAME_OUTSIDE_TEMPLATE SDockTab::FArguments()

TYPENAME_OUTSIDE_TEMPLATE 的定义如下

#if !defined(__clang__)		// Clang expects typename outside template
	#define TYPENAME_OUTSIDE_TEMPLATE
#endif

C/C++:函数名前引用一个空的宏定义 (https://blog.csdn.net/qq_30015903/article/details/88039320)
最后说操作符重载 <<= ,这个操作符是在 TDecl 类中重载的,具体类型替换后

/**
	 * Complete widget construction from InArgs.
	 *
	 * @param InArgs  NamedArguments from which to construct the widget.
	 *
	 * @return A reference to the widget that we constructed.
	 */
	TSharedRef<SDockTab> operator<<=( const typename SDockTab::FArguments& InArgs ) const
	{
		//@todo UMG: This should be removed in favor of all widgets calling their superclass construct.
		_Widget->SWidgetConstruct(
			InArgs._ToolTipText,
			InArgs._ToolTip,
			InArgs._Cursor,
			InArgs._IsEnabled,
			InArgs._Visibility,
			InArgs._RenderOpacity,
			InArgs._RenderTransform,
			InArgs._RenderTransformPivot,
			InArgs._Tag,
			InArgs._ForceVolatile,
			InArgs._Clipping,
			InArgs._FlowDirectionPreference,
			InArgs._AccessibleText.IsSet() ? FAccessibleWidgetData(InArgs._AccessibleText) : InArgs._AccessibleParams,
			InArgs.MetaData );

		_RequiredArgs.CallConstruct(_Widget, InArgs);

		return _Widget;
	}

所以宏SNew 就是返回一个 初始化后的TSharedRef 共享引用

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值