UE4c++ Slate整套学习流程(源码编译+Slate框架+SlateViewer)

UE4c++ Slate整套学习流程(WidgetReflector的使用+源码编译+Slate基本实现原理+SlateViewer)

前言
Slate是构成UE引擎整套UI框架底层的基石,而我们平常蓝图开发的虽然是UMG一套,也就是继承自UWidget,可能感觉是与继承自SWidget的Slate开发流程有些区别,但是本质上UWidget也是采用的是SWidget这套流程,甚至我们再其中还能看到许多存储了SWidget的变量,如下图所示。区别是UWidget是面向用户层的,因此其中有很多方法都是反射到蓝图上使用的,在开发过程中,许多繁琐的UI用UMG实现起来实在是很困难,列如各自表图(类似于EChart中的图表数据),而且我们在开发编辑器插件过程中如果想使用一些UI来进行简单的交互,那Slate的学习不得不提早进入学习档期。虽然有很多文章,包括我之前也简单的对Slate进行了梳理,但是总觉得缺少了一些东西。
在这里插入图片描述

WidgetReflector的使用(会的人跳过这部分即可)

  • who:WidgetReflector是什么?WidgetReflector是用于开发者快速追踪定位UI的。
  • why:为什么要学习使用WidgetReflector开发者工具?在学习过程中我们可以用它快速追踪到UI的一些基本架构,也能给自己提供思路,如何去学习实现这套UI框架搭建。

首先先打开WidgetReflector
在这里插入图片描述
常用的,就是获取绘制的UI(Hit-Testable)与获取可交互的UI(Painted)俩种模式
在这里插入图片描述
点击之后我们发现鼠标样式变了
在这里插入图片描述
按ECS键结束状态并选中当前鼠标所执行的UI,双击我们就能跟踪到UI定义的位置,包括UMG与源码中的SWidget内容,而且他的结构与我们常见的UMG结构看着很类似,在其中也能充分体现出UI层级结构
在这里插入图片描述

源码编译

为什么要编译源码?Slate学习必须要用到源码吗?
想必很多小伙伴有很多疑问,在此我一一解答,编译源码的原因是为了我们之间从官方SlateViewer开始学习,什么是SlateViewer那就是接下来讲解的内容了,Slate的学习根据自己的能力,也不一定用源码,比如可以创建用常见的窗口插件,在其中练习自己的Slate,源码的编译过程,也能加大大家对于UE的熟悉度,增大对于看源码的过程。
这个就直接附着链接了
UE的源码引擎下载编译

Slate基本实现原理在此附着了我之前文章讲解的slate的原理,让大家知道为什么Slate语法能这样写)

Slate是UE的一套GUI框架,也是构成UE的UI基元

  • 模块添加
    在这里插入图片描述
    打开你的项目的[项目名称].build.cs 文件,添加要使用到的模块
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
  • 控件显示
    为了在你的游戏中显示一个Slate控件,则必须将该控件添加到游戏视口中。到当前游戏视口的引用可以通过 UEngine 的 GameViewport 成员获得。GEngine->GameViewport
GEngine->GameViewport->AddViewportWidgetContent(
    SNew(MyWidgetPtr.ToSharedRef())
);
  • 从视口中删除控件
//删除对应Widget
GEngine->GameViewport->RemoveViewportWidgetContent(
    SNew(MyWidgetPtr.ToSharedRef())
);
//删除所有的Widget
GEngine->GameViewport->RemoveAllViewportWidgets();
  • 2.正文
    在这里插入图片描述

以ColorPick举例,使用控件反射器去跟踪Slate结构在这里插入图片描述
参考下图与代码,我们可以看到Slate是很具有结构性的,其实参考代码不难看出它俩之间的联系
在这里插入图片描述

	SmallTrash = SNew(SHorizontalBox)
	+ SHorizontalBox::Slot()
		.AutoWidth()
		[
			SNew(SColorTrash)
				.UsesSmallIcon(true)
		];
	
	this->ChildSlot
	[
		SNew(SVerticalBox)

		+ SVerticalBox::Slot()
			.AutoHeight()
			[
				SNew(SGridPanel)
					.FillColumn(0, 1.0f)

				+ SGridPanel::Slot(0, 0)
					.Padding(0.0f, 1.0f, 20.0f, 1.0f)
					[
						SNew(SHorizontalBox)

						+ SHorizontalBox::Slot()
							.FillWidth(1.0f)
							.Padding(0.0f, 1.0f)
							[
								SNew(SOverlay)

								+ SOverlay::Slot()
									[
										// color theme bar
										SAssignNew(CurrentThemeBar, SThemeColorBlocksBar)
											.ColorTheme(this, &SColorPicker::HandleThemeBarColorTheme)
											.EmptyText(LOCTEXT("EmptyBarHint", "Drag & drop colors here to save"))
											.HideTrashCallback(this, &SColorPicker::HideSmallTrash)
											.ShowTrashCallback(this, &SColorPicker::ShowSmallTrash)
											.ToolTipText(LOCTEXT("CurrentThemeBarToolTip", "Current Color Theme"))
											.UseAlpha(SharedThis(this), &SColorPicker::HandleThemeBarUseAlpha)
											.UseSRGB(SharedThis(this), &SColorPicker::HandleColorPickerUseSRGB)
											.OnSelectColor(this, &SColorPicker::HandleThemeBarColorSelected)
									]

								// hack: need to fix SThemeColorBlocksBar::EmptyText to render properly
								+ SOverlay::Slot()
									.HAlign(HAlign_Center)
									.VAlign(VAlign_Center)
									[
										SNew(STextBlock)
										.Text(LOCTEXT("EmptyBarHint", "Drag & drop colors here to save"))
										.Visibility(this, &SColorPicker::HandleThemeBarHintVisibility)
									]
							]

						+ SHorizontalBox::Slot()
							.AutoWidth()
							[
								// color theme selector
								SAssignNew(ColorThemeButtonOrSmallTrash, SBorder)
									.BorderImage(FStyleDefaults::GetNoBrush())
									.Padding(0.0f)
							]
					]

				+ SGridPanel::Slot(1, 0)
					.HAlign(HAlign_Right)
					.VAlign(VAlign_Center)
					[
						// sRGB check box
						SNew(SCheckBox)
							.ToolTipText(LOCTEXT("SRGBCheckboxToolTip", "Toggle gamma corrected sRGB previewing"))
							.IsChecked(this, &SColorPicker::HandleSRGBCheckBoxIsChecked)
							.OnCheckStateChanged(this, &SColorPicker::HandleSRGBCheckBoxCheckStateChanged)
							[
								SNew(STextBlock)
									.Text(LOCTEXT("SRGBCheckboxLabel", "sRGB Preview"))
							]
					]

				+ SGridPanel::Slot(0, 1)
					.Padding(0.0f, 8.0f, 20.0f, 0.0f)
					[
						SNew(SBorder)
							.BorderImage(FCoreStyle::Get().GetBrush("NoBorder"))
							.Padding(0.0f)
							.OnMouseButtonDown(this, &SColorPicker::HandleColorAreaMouseDown)
							[
								SNew(SOverlay)

								// color wheel
								+ SOverlay::Slot()
									[
										SNew(SHorizontalBox)

										+ SHorizontalBox::Slot()
											.FillWidth(1.0f)
											.HAlign(HAlign_Center)
											[
												SNew(SColorWheel)
													.SelectedColor(this, &SColorPicker::GetCurrentColor)
													.Visibility(this, &SColorPicker::HandleColorPickerModeVisibility, EColorPickerModes::Wheel)
													.OnValueChanged(this, &SColorPicker::HandleColorSpectrumValueChanged)
													.OnMouseCaptureBegin(this, &SColorPicker::HandleInteractiveChangeBegin)
													.OnMouseCaptureEnd(this, &SColorPicker::HandleInteractiveChangeEnd)
											]

										+ SHorizontalBox::Slot()
											.AutoWidth()
											.Padding(4.0f, 0.0f)
											[
												// saturation slider
												MakeColorSlider(EColorPickerChannels::Saturation)
											]

										+ SHorizontalBox::Slot()
											.AutoWidth()
											[
												// value slider
												MakeColorSlider(EColorPickerChannels::Value)
											]
									]

								// color spectrum
								+ SOverlay::Slot()
									[
										SNew(SBox)
											.HeightOverride(200.0f)
											.WidthOverride(292.0f)
											[
												SNew(SColorSpectrum)
													.SelectedColor(this, &SColorPicker::GetCurrentColor)
													.Visibility(this, &SColorPicker::HandleColorPickerModeVisibility, EColorPickerModes::Spectrum)
													.OnValueChanged(this, &SColorPicker::HandleColorSpectrumValueChanged)
													.OnMouseCaptureBegin(this, &SColorPicker::HandleInteractiveChangeBegin)
													.OnMouseCaptureEnd(this, &SColorPicker::HandleInteractiveChangeEnd)
											]
									]
							]
					]

				+ SGridPanel::Slot(1, 1)
					.Padding(0.0f, 8.0f, 0.0f, 0.0f)
					[
						SNew(SVerticalBox)

						+ SVerticalBox::Slot()
							.AutoHeight()
							[
								SNew(SBox)
									.HeightOverride(100.0f)
									.WidthOverride(70.0f)
									[
										// color preview
										MakeColorPreviewBox()
									]
							]

						+ SVerticalBox::Slot()
							.AutoHeight()
							.Padding(0.0f, 16.0f, 0.0f, 0.0f)
							.VAlign(VAlign_Top)
							[
								SNew(SHorizontalBox)

								+ SHorizontalBox::Slot()
									.HAlign(HAlign_Left)
									[
										// mode selector
										SNew(SButton)
											.OnClicked(this, &SColorPicker::HandleColorPickerModeButtonClicked)
											.Content()
											[
												SNew(SImage)
													.Image(FCoreStyle::Get().GetBrush("ColorPicker.Mode"))
													.ToolTipText(LOCTEXT("ColorPickerModeEToolTip", "Toggle between color wheel and color spectrum."))
											]									
									]

								+ SHorizontalBox::Slot()
									.HAlign(HAlign_Right)
									[
										// eye dropper
										SNew(SEyeDropperButton)
											.OnValueChanged(this, &SColorPicker::HandleRGBColorChanged)
											.OnBegin(this, &SColorPicker::HandleInteractiveChangeBegin)
											.OnComplete(this, &SColorPicker::HandleEyeDropperButtonComplete)
											.DisplayGamma(DisplayGamma)
											.Visibility(bValidCreationOverrideExists ? EVisibility::Collapsed : EVisibility::Visible)
									]
							]
					]
			]

		// advanced settings
		+ SVerticalBox::Slot()
			.AutoHeight()
			.Padding(0.0f, 4.0f, 0.0f, 0.0f)
			[
				SNew(SExpandableArea)
					.AreaTitle(LOCTEXT("AdvancedAreaTitle", "Advanced"))
					.BorderBackgroundColor(FLinearColor::Transparent)
					.InitiallyCollapsed(!bAdvancedSectionExpanded)
					.OnAreaExpansionChanged(this, &SColorPicker::HandleAdvancedAreaExpansionChanged)
					.Padding(FMargin(0.0f, 1.0f, 0.0f, 8.0f))
					.BodyContent()
					[
						SNew(SHorizontalBox)

						// RGBA inputs
						+ SHorizontalBox::Slot()
							.Padding(0.0f, 0.0f, 4.0f, 0.0f)
							[
								SNew(SVerticalBox)

								// Red
								+ SVerticalBox::Slot()
									[
										MakeColorSpinBox(EColorPickerChannels::Red)
									]

								// Green
								+ SVerticalBox::Slot()
									.Padding(0.0f, 8.0f, 0.0f, 0.0f)
									[
										MakeColorSpinBox(EColorPickerChannels::Green)
									]

								// Blue
								+ SVerticalBox::Slot()
									.Padding(0.0f, 8.0f, 0.0f, 0.0f)
									[
										MakeColorSpinBox(EColorPickerChannels::Blue)
									]

								// Alpha
								+ SVerticalBox::Slot()
									.Padding(0.0f, 8.0f, 0.0f, 0.0f)
									[
										MakeColorSpinBox(EColorPickerChannels::Alpha)
									]
							]

						// HSV & Hex inputs
						+ SHorizontalBox::Slot()
							.Padding(4.0f, 0.0f, 0.0f, 0.0f)
							[
								SNew(SVerticalBox)
							
								// Hue
								+ SVerticalBox::Slot()
								[
									MakeColorSpinBox(EColorPickerChannels::Hue)
								]

								// Saturation
								+ SVerticalBox::Slot()
								.Padding(0.0f, 8.0f, 0.0f, 0.0f)
								[
									MakeColorSpinBox(EColorPickerChannels::Saturation)
								]

								// Value
								+ SVerticalBox::Slot()
								.Padding(0.0f, 8.0f, 0.0f, 0.0f)
								[
									MakeColorSpinBox(EColorPickerChannels::Value)
								]

								// Hex linear
								+ SVerticalBox::Slot()
									.HAlign(HAlign_Right)
									.VAlign(VAlign_Top)
									.Padding(0.0f, 12.0f, 0.0f, 0.0f)
									[
										SNew(SHorizontalBox)
											.ToolTipText(LOCTEXT("HexLinearSliderToolTip", "Hexadecimal Linear Value"))

										+ SHorizontalBox::Slot()
											.AutoWidth()
											.Padding(0.0f, 0.0f, 4.0f, 0.0f)
											.VAlign(VAlign_Center)
											[
												SNew(STextBlock)
													.Text(LOCTEXT("HexLinearInputLabel", "Hex Linear"))
											]

										+ SHorizontalBox::Slot()
											.AutoWidth()
											.MaxWidth(72.0f)
											[
												SNew(SEditableTextBox)
													.MinDesiredWidth(72.0f)
													.Text(this, &SColorPicker::HandleHexLinearBoxText)
													.OnTextCommitted(this, &SColorPicker::HandleHexLinearInputTextCommitted)
											]
								]

								// Hex sRGB
								+ SVerticalBox::Slot()
									.HAlign(HAlign_Right)
									.VAlign(VAlign_Top)
									.Padding(0.0f, 8.0f, 0.0f, 0.0f)
									[
										SNew(SHorizontalBox)
										.ToolTipText(LOCTEXT("HexSRGBSliderToolTip", "Hexadecimal sRGB Value"))

										+ SHorizontalBox::Slot()
											.AutoWidth()
											.Padding(0.0f, 0.0f, 4.0f, 0.0f)
											.VAlign(VAlign_Center)
											[
												SNew(STextBlock)
												.Text(LOCTEXT("HexSRGBInputLabel", "Hex sRGB"))
											]

										+ SHorizontalBox::Slot()
											.AutoWidth()
											.MaxWidth(72.0f)
											[
												SNew(SEditableTextBox)
												.MinDesiredWidth(72.0f)
												.Text(this, &SColorPicker::HandleHexSRGBBoxText)
												.OnTextCommitted(this, &SColorPicker::HandleHexSRGBInputTextCommitted)
											]
								]
						]
				]
			]

		// dialog buttons
		+ SVerticalBox::Slot()
			.AutoHeight()
			.HAlign(HAlign_Right)
			.VAlign(VAlign_Center)
			.Padding(0.0f, 12.0f, 0.0f, 0.0f)
			[
				SNew(SUniformGridPanel)
					.MinDesiredSlotHeight(FCoreStyle::Get().GetFloat("StandardDialog.MinDesiredSlotHeight"))
					.MinDesiredSlotWidth(FCoreStyle::Get().GetFloat("StandardDialog.MinDesiredSlotWidth"))
					.SlotPadding(FCoreStyle::Get().GetMargin("StandardDialog.SlotPadding"))
					.Visibility((ParentWindowPtr.IsValid() || bValidCreationOverrideExists) ? EVisibility::Visible : EVisibility::Collapsed)

				+ SUniformGridPanel::Slot(0, 0)
					[
						// ok button
						SNew(SButton)
							.ContentPadding( FCoreStyle::Get().GetMargin("StandardDialog.ContentPadding") )
							.HAlign(HAlign_Center)
							.Text(LOCTEXT("OKButton", "OK"))
							.OnClicked(this, &SColorPicker::HandleOkButtonClicked)
					]

				+ SUniformGridPanel::Slot(1, 0)
					[
						// cancel button
						SNew(SButton)
							.ContentPadding( FCoreStyle::Get().GetMargin("StandardDialog.ContentPadding") )
							.HAlign(HAlign_Center)
							.Text(LOCTEXT("CancelButton", "Cancel"))
							.OnClicked(this, &SColorPicker::HandleCancelButtonClicked)
					]
			]
	];

对比代码与Slate层级之后,我们发现Slate编程有些奇怪,但很具有结构,而Slate为什么会能这样连写呢,第一反应有人觉得这是C++语法吗,请接着往下看。
在这里插入图片描述
注:宏定义#表示链接,\用于作换行
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可连续用点是因为返回值类型全是自身,就一直调用自己的方法,再将自己返回出去
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

它也对+号等进行了重载
在这里插入图片描述
在这类建立时候,用SLATE_BEGIN_ARGS宏进行了这些基础方法的生成与实现,因此,这是导致Slate语法奇怪的原因,当你知道了这些重载之后再来看Slate语法将会恍然大悟。
列如下图:创窗口设置大小为(541,632),绑定了窗口名字的Lamda表达式,设置其名字为ColorPicker,接下来的操作大家多去看看大概就明白什么意思了。
在这里插入图片描述

SlateViewer

SlateViewer是属于UE源码引擎的一套官方提供给大众学习观看Slate的最佳途径
首先打开UE源码,将SlateViewer设置为启动项
在这里插入图片描述
下面则是点击运行之后得到的,其中几乎将UE整套UI模块,包括部分渲染模块都包含了,因此我们用它去对Slate学习更轻松
请添加图片描述
在此我们看到了熟悉的c++Win32程序的函数入口,WinMain函数,其中调用了我们Slate启动起来的方法
在这里插入图片描述
这个方法也相较于比较简单,便于我们轻松的去查看Slate实现的基本原理

int RunSlateViewer( const TCHAR* CommandLine )
{
    
    
	// start up the main loop
	GEngineLoop.PreInit(CommandLine);

	// Make sure all UObject classes are registered and default properties have been initialized
	ProcessNewlyLoadedUObjects();
	
	// Tell the module manager it may now process newly-loaded UObjects when new C++ modules are loaded
	FModuleManager::Get().StartProcessingNewlyLoadedObjects();

	// crank up a normal Slate application using the platform's standalone renderer
	FSlateApplication::InitializeAsStandaloneApplication(GetStandardStandaloneRenderer());

	// Load the source code access module
	ISourceCodeAccessModule& SourceCodeAccessModule = FModuleManager::LoadModuleChecked<ISourceCodeAccessModule>( FName( "SourceCodeAccess" ) );
	
	// Manually load in the source code access plugins, as standalone programs don't currently support plugins.
#if PLATFORM_MAC
	IModuleInterface& XCodeSourceCodeAccessModule = FModuleManager::LoadModuleChecked<IModuleInterface>( FName( "XCodeSourceCodeAccess" ) );
	SourceCodeAccessModule.SetAccessor(FName("XCodeSourceCodeAccess"));
#elif PLATFORM_WINDOWS
	IModuleInterface& VisualStudioSourceCodeAccessModule = FModuleManager::LoadModuleChecked<IModuleInterface>( FName( "VisualStudioSourceCodeAccess" ) );
	SourceCodeAccessModule.SetAccessor(FName("VisualStudioSourceCodeAccess"));
#endif

	// set the application name
	FGlobalTabmanager::Get()->SetApplicationTitle(LOCTEXT("AppTitle", "Slate Viewer"));
	FModuleManager::LoadModuleChecked<ISlateReflectorModule>("SlateReflector").RegisterTabSpawner(WorkspaceMenu::DeveloperMenu);

	FGlobalTabmanager::Get()->RegisterNomadTabSpawner("WebBrowserTab", FOnSpawnTab::CreateStatic(&SpawnWebBrowserTab))
		.SetDisplayName(LOCTEXT("WebBrowserTab", "Web Browser"));
	
	if (FParse::Param(FCommandLine::Get(), TEXT("perftest")))
	{
    
    
		// Bring up perf test
		SummonPerfTestSuite();
	}
	else
	{
    
    
		// Bring up the test suite.
		RestoreSlateTestSuite();
	}


#if WITH_SHARED_POINTER_TESTS
	SharedPointerTesting::TestSharedPointer<ESPMode::Fast>();
	SharedPointerTesting::TestSharedPointer<ESPMode::ThreadSafe>();
#endif

	// loop while the server does the rest
	while (!IsEngineExitRequested())
	{
    
    
		FTaskGraphInterface::Get().ProcessThreadUntilIdle(ENamedThreads::GameThread);
		FStats::AdvanceFrame(false);
		FTicker::GetCoreTicker().Tick(FApp::GetDeltaTime());
		FSlateApplication::Get().PumpMessages();
		FSlateApplication::Get().Tick();		
		FPlatformProcess::Sleep(0);
	}

	FCoreDelegates::OnExit.Broadcast();
	FSlateApplication::Shutdown();
	FModuleManager::Get().UnloadModulesAtShutdown();


	return 0;
}

有些的定义在其他模块或者宏里面,大家查找时候一定要仔细,例如GEngineLoop
在这里插入图片描述
在这里插入图片描述
FSlateApplication::InitializeAsStandaloneApplication(GetStandardStandaloneRenderer());启用了渲染模块,对于渲染感兴趣的,看这个模块也不错,SlateViewer渲染模块

比如生成Web浏览器选项卡内容
在这里插入图片描述
这里加载了SlateReflector模块
在这里插入图片描述
这里创建了我们的测试窗口
在这里插入图片描述
切入可以看到其中如何创建的我们看见的UI页面,对于这块感兴趣的小伙伴可以自己切入源码看看,在这就不附图了
这个类中也可以看到我们刚熟悉的Slate语法
在这里插入图片描述
到此感谢各位小伙伴的观看大家可以对于自己喜欢的模块进行专研

猜你喜欢

转载自blog.csdn.net/weixin_56946623/article/details/126990479