UE4笔记-UMG和Slate记录
個(gè)人開(kāi)發(fā)記錄筆記,隨緣更新
UMG和Slate都屬于UE4的UI系統(tǒng)的一部分:
整套布局系統(tǒng)是很標(biāo)準(zhǔn)的C/S方式(Qt/WinForm)
UMG是基于原先的Slate封裝開(kāi)發(fā)的GUI.UE4提供了可視化編輯器用于用戶編輯自己GUI系統(tǒng)同時(shí)UMG組件還添加了很多事件和方法并支持BP
Slate則是完全C++代碼化的,所有的布局和組件創(chuàng)建只能用C++實(shí)現(xiàn)(Slate有一些更底層的組件,如SSplitter等,更便于開(kāi)發(fā)復(fù)雜UI).
這篇隨筆用于記錄一些文檔以外一些UMG和Slate的一些問(wèn)題和混用例子(UPanelWidget和UContentWidget)
Umg文檔:http://api.unrealengine.com/INT/Engine/UMG/index.html
Slate文檔:http://api.unrealengine.com/INT/Programming/Slate/index.html
其他一些文章Mark:
[UE4]Slate and Native UMG(C++) Notes:https://dawnarc.com/2018/12/ue4slate-and-native-umgc-notes/
Q.生命周期:
UMG是居于UOBJECT的而Slate卻是居于TSharedFromThis,所以UMG可以暴露于BP,而Slate只能應(yīng)用于C++,而且聲明周期也不盡相同:
wait
Umg:
Slate:
(懶癌附體,康心情補(bǔ)充)
Q.創(chuàng)建細(xì)節(jié):
Umg:
關(guān)于創(chuàng)建對(duì)象:
因?yàn)閁MG大多數(shù)都是BP類,所以當(dāng)需要在C++創(chuàng)建時(shí),需要通過(guò)TSubclassOf將BP類傳回C++或使用LoadClass引用BP類:
note:
1.通常創(chuàng)建使用CreateWidget 函數(shù),但是,如果想創(chuàng)建非UserWidget的類,如,UButton 等UContentWidget或UPanelWidget,可以用Construct Object from class函數(shù)來(lái)創(chuàng)建.免去無(wú)意義UUserWidget 封裝
C++創(chuàng)建BP類Widget的栗子:
UUserWidget* AMyProject2Character::CreateBPUserWidget(TSubclassOf<UUserWidget> SpecificBPClass)
{
     UUserWidget *newUserWidget = nullptr;
	    UClass *SpecificBPClassFromCPlusPlus = LoadClass<UUserWidget>(NULL, TEXT("/Game/Blueprints/BPBaseWgt.BPBaseWgt_C"));
	    if (SpecificBPClassFromCPlusPlus) 
	    {
		      newUserWidget = CreateWidget<UUserWidget>(UGameplayStatics::GetPlayerController(GetWorld(), 0), SpecificBPClassFromCPlusPlus);
		      check(newUserWidget)
	    }
return newUserWidget;
}
關(guān)于UMG的C++與BP的混合使用:
通常都會(huì)定義一個(gè)C++的UUserWidget類來(lái)作為BP UMG的基類,以暴露一些BP變量到C++中,
一般不熟悉的情況下,會(huì)在BP中的PreConstruct 或Construct 事件下手動(dòng)賦值到C++定義的變量上。
事實(shí)上,可以選擇使用UPROPERTY的Meta宏進(jìn)行自動(dòng)綁定
如:綁定Editor編輯器定義的UMG的控件控件和動(dòng)畫類到C++基類的變量上
    UPROPERTY(BlueprintReadOnly, Category = "MainWidget", Meta = (BindWidget))
        UHorizontalBox *Container = nullptr;
    UPROPERTY(BlueprintReadOnly, Category = "MainWidget", Meta = (BindWidgetAnim))
        class UWidgetAnimation* Anim_Container = nullptr;
當(dāng)UMG繼承了該基類,UE4會(huì)自動(dòng)跟BP中名為Container 的容器和Anim_Container的動(dòng)畫 綁定
Slate的創(chuàng)建:
Slate在C++中則是使用類似如下的方式創(chuàng)建:
TSharedPtr<SMySlateWidget> slateWidget = SNew(SMySlateWidget);
或
TSharedPtr<SMySlateWidget> MySlateWidget;
TSharedRef<SSplitter> MyWgtRef = SAssignNew( MySlateWidget, SMySlateWidget);
貼出SMySlateWidget實(shí)現(xiàn):
.h
#pragma once
#include "CoreMinimal.h"
#include "SUserWidget.h"
class MYPROJECT2_API SMySlateWidget : public SUserWidget
{
public:
    SLATE_USER_ARGS(SMySlateWidget)
    {}
    SLATE_END_ARGS()
public:
    virtual void Construct(const FArguments& InArgs);
protected:
    FSlateBrush brush;
};
.cpp
#include "SMySlateWidget.h"
#include "Slate.h"
#include "SConstraintCanvas.h"
void SMySlateWidget::Construct(const FArguments& InArgs)
{
    TSharedRef<SBorder> border = SNew(SBorder);
    border->SetBorderBackgroundColor(FLinearColor::Red);
    border->SetForegroundColor(FLinearColor(0, 255, 0, 0.5));
    border->SetBorderImage(&brush);
    border->SetColorAndOpacity(FLinearColor::Green);
    SConstraintCanvas::FSlot &temp_slot = SConstraintCanvas::Slot();
    temp_slot.Anchors(FAnchors(0.0f, 0.0f, 1.0f, 1.0f))
        .Offset(FMargin(100.0f, 100.0f, 100.0f, 100.0f))
        .ZOrder(1)
        .AttachWidget(border);
    SUserWidget::Construct(
                            SUserWidget::FArguments()
                            [
                                SNew(SConstraintCanvas) + temp_slot
                            ] 
                          );
}
TSharedRef<SMySlateWidget> SMySlateWidget::New()
{
    return MakeShareable(new SMySlateWidget());
}
Q.在Slate中使用UMG組件:
方法一:
使用TakeWidget();函數(shù)轉(zhuǎn)換成Slate即可
//temporary_wgt 是你的UUserWIdget類實(shí)例
    TSharedRef<SWidget> border = temporary_wgt->TakeWidget();
例如在RebuildWidget中:
TSharedRef<SWidget> UCppWgt_BaseSplitter::RebuildWidget()
{
//temporary_wgt 是你的UUserWIdget類實(shí)例,自行Create Widget
TSharedRef<SWidget> border = temporary_wgt->TakeWidget();
SConstraintCanvas::FSlot &temp_slot = SConstraintCanvas::Slot();
    temp_slot.Anchors(FAnchors(0.0f, 0.0f, 1.0f, 1.0f))
        .Offset(FMargin(100.0f, 100.0f, 100.0f, 100.0f))
        .ZOrder(1)
        .AttachWidget(container);
    auto ret_wgt = SNew(SConstraintCanvas) + temp_slot;
    return  ret_wgt;
}
Q.混合使用:
方法一(覆蓋形式):
如果想在UMG添加一個(gè)Slate的組件,那么你可以用UWidget子類簡(jiǎn)單封裝一下,重載RebuildWidget,使用Slate的Widget來(lái)完全覆蓋代替
這里就用上面創(chuàng)建的Slate:SMySlateWidget
例子:
.h
UCLASS()
class 項(xiàng)目_API UContenSlateWidget : public UUserWidget { GENERATED_BODY() public :
virtual const FText GetPaletteCategory() override; protected: virtual TSharedRef<SWidget> RebuildWidget() override; };
.cpp
const FText UContenSlateWidget::GetPaletteCategory()
{
    return NSLOCTEXT("UContenSlatetWidget","MyCustomSlate", "CustomSlate");
}
TSharedRef<SWidget> UContenSlateWidget::RebuildWidget() 
{
    TSharedRef<SMySlateWidget> mySlateCom = SNew(SMySlateWidget);
    
    return mySlateCom;
}
方法二:
重寫RebuildWidget是混用最簡(jiǎn)單的方式,但是卻無(wú)法在UMG編輯器里二次編輯擴(kuò)展UMG類.
那么如果有相關(guān)需求,這個(gè)時(shí)候可以考慮TakeDerivedWidget函數(shù)來(lái)代替重寫RebuildWidget的方式
栗子:
待添加
Q.UPanelWidget和UContentWidget分析和栗子:
UPanelWidget和UContentWidget都是Slate對(duì)UMG暴露的封裝基礎(chǔ)實(shí)現(xiàn)類.
如UE4自帶的UI組件:Border,Canvas,VerticalBox,SButton等都是基于以上兩個(gè)類繼承實(shí)現(xiàn)的
當(dāng)你需要封裝一些自定義組件的時(shí)候,可以繼承它們或它們的子類
note:UContentWidget是UPanelWidget的子類,基于UPanelWidget重新封裝實(shí)現(xiàn)的.
區(qū)別是:
UPanelWidget是多個(gè)Slot的組件:例如VerticalBox
UContentWidget是單個(gè)Slot的組件:例如Border,Button
源碼分析:
UPanelWidget:
wait(懶癌附體,康心情補(bǔ)充)
UContentWidget:
wait(懶癌附體,康心情補(bǔ)充)
例子:
基于UPanelWidget 自定義一個(gè)UMG 的Splitter的布局組件(CppWgt_SpliterComponent):
需要擴(kuò)展兩個(gè)分別繼承于UPanelSlot,UPanelWidget的類
USplitterComponentSlot 和
CppWgt_SpliterComponent
Note:(這里只是對(duì)Spliter簡(jiǎn)單的UMG封裝,需要自己根據(jù)情況擴(kuò)展)
USplitterComponentSlot .h
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "UObject/ScriptMacros.h"
#include "Components/PanelSlot.h"
#include "Components/SlateWrapperTypes.h"
#include "Runtime/Slate/Public/Widgets/Layout/SSplitter.h"
#include "SplitterComponentSlot.generated.h"
UCLASS()
class 項(xiàng)目_API USplitterComponentSlot : public UPanelSlot
{
    GENERATED_UCLASS_BODY()
public :
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Layout|SSpliter Slot")
        float SizeValue = 1.0f;
public:
    void BuildSlot(TSharedRef<SSplitter> SplitterCom);
    // UPanelSlot interface
    virtual void SynchronizeProperties() override;
    // End of UPanelSlot interface
    virtual void ReleaseSlateResources(bool bReleaseChildren) override;
private:
    SSplitter::FSlot* Slot;
};
USplitterComponentSlot .cpp
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
#include "SplitterComponentSlot.h"
#include "Components/Widget.h"
/////////////////////////////////////////////////////
// UHorizontalBoxSlot
USplitterComponentSlot::USplitterComponentSlot(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{
    Slot = NULL;
}
void USplitterComponentSlot::ReleaseSlateResources(bool bReleaseChildren)
{
    Super::ReleaseSlateResources(bReleaseChildren);
    Slot = NULL;
}
void USplitterComponentSlot::BuildSlot(TSharedRef<SSplitter> SplitterCom)
{
    Slot = &SplitterCom->AddSlot()
    [
        Content == NULL ? SNullWidget::NullWidget : Content->TakeWidget()
    ].Value(SizeValue);
}
void USplitterComponentSlot::SynchronizeProperties()
{
}
CppWgt_SpliterComponent.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Runtime/UMG/Public/Components/PanelWidget.h"
#include "CppWgt_SpliterComponent.generated.h"
/**
 * 
 */
UCLASS()
class 項(xiàng)目_API UCppWgt_SpliterComponent : public UPanelWidget
{
    GENERATED_BODY()
public:
#if WITH_EDITOR
    // UWidget interface
    virtual const FText GetPaletteCategory() override;
    // End UWidget interface
#endif
    virtual void ReleaseSlateResources(bool bReleaseChildren) override;
protected:
    // UPanelWidget
    virtual UClass* GetSlotClass() const override;
    virtual void OnSlotAdded( UPanelSlot* Slot) override;
    virtual void OnSlotRemoved(UPanelSlot* Slot) override;
    // End UPanelWidget
protected:
    TSharedPtr<class SSplitter> MySplitter;
protected:
    // UWidget interface
    virtual TSharedRef<SWidget> RebuildWidget() override;
    // End of UWidget interface
};
CppWgt_SpliterComponent.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "CppWgt_SpliterComponent.h"
#include "Components/Border.h"
#include "Runtime/Slate/Public/Widgets/Layout/SBorder.h"
#include "Runtime/UMG/Public/Components/PanelSlot.h"
#include "SplitterComponentSlot.h"
#define LOCTEXT_NAMESPACE "UMG"
const FText UCppWgt_SpliterComponent::GetPaletteCategory()
{
    //UE_LOG(LogTemp, Log, TEXT(" GetPaletteCategory "));
    return LOCTEXT("", "QingUI");
}
void UCppWgt_SpliterComponent::ReleaseSlateResources(bool bReleaseChildren)
{
    Super::ReleaseSlateResources(bReleaseChildren);
    MySplitter.Reset();
}
UClass * UCppWgt_SpliterComponent::GetSlotClass() const
{
    UE_LOG(LogTemp, Log, TEXT(" GetSlotClass "));
    return USplitterComponentSlot::StaticClass();
}
void UCppWgt_SpliterComponent::OnSlotAdded(UPanelSlot * Slot)
{
    if (!MySplitter.IsValid())
    {
        return;
    }
    UE_LOG(LogTemp, Log, TEXT(" OnSlotAdded "));
    CastChecked< USplitterComponentSlot>(Slot)->BuildSlot(MySplitter.ToSharedRef());
}
void UCppWgt_SpliterComponent::OnSlotRemoved(UPanelSlot * Slot)
{
    //這里
   TSharedPtr<SWidget> Widget = Slot->Content->GetCachedWidget();
	  if ( !MySplitter.IsValid() || 
		     !Widget.IsValid() )
	  {
		    return;
	  }
FChildren* Children = MySplitter->GetChildren();
   for (int i = 0; i < Children->Num(); i++ ) 
	  {
		    TSharedRef<SWidget> tempWgt = Children->GetChildAt(i);
     if (Widget == tempWgt)
		    {
			      //Widget->SetVisibility(EVisibility::Hidden);
			      MySplitter->RemoveAt(i);
			      break;
		    }
	  }
}
TSharedRef<SWidget> UCppWgt_SpliterComponent::RebuildWidget()
{
    MySplitter = SNew(SSplitter);
    
    for (UPanelSlot* PanelSlot : Slots) 
    {
        if (USplitterComponentSlot* TypedSlot = Cast<USplitterComponentSlot>(PanelSlot))
        {
            TypedSlot->Parent = this;
            TypedSlot->BuildSlot(MySplitter.ToSharedRef());
        }
    }
    
    return MySplitter.ToSharedRef();
}
#undef LOCTEXT_NAMESPACE
                            總結(jié)
以上是生活随笔為你收集整理的UE4笔记-UMG和Slate记录的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
 
                            
                        - 上一篇: 扫雷网页版
- 下一篇: 中文输入法不触发onkeyup事件的解决
