Unreal Engine 4 C++ UMG自定义控件

Unreal Engine 4 C++ UMG自定义控件

好记性不如烂笔头啊,还是记录一下!


如果你觉得Unreal Engine里面的控件没有达到你的需求,你需要添加自定控件。


创建Slate控件

如果你还不了解如何创建一个Slate控件,请先阅读:

Unreal Engine 4 C++ Slate 介绍——用C++和Slate创建菜单(一)

Unreal Engine 4 C++ Slate 介绍——用C++和Slate创建菜单(二)

Unreal Engine 4 C++ Slate 介绍——用C++和Slate创建菜单(三)

这里用我自己写的作为参考:

  • SProgressBarEx.h
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "UI/Slate/ProgressBarExStyle.h"

/**
 *  SProgressBarEx Fill Type 
 */
UENUM(BlueprintType)
namespace EProgressBarExFillType
{
    enum Type
    {
        // will fill up from the left side to the right
        LeftToRight,
        // will fill up from the right side to the left side
        RightToLeft,
        // will fill up from the center to the outer edges
        FillFromCenter,
        // will fill up from the top to the the bottom
        TopToBottom,
        // will fill up from the bottom to the the top
        BottomToTop,
    };
}

/** A progress extend bar widget.*/
class TESTMOBILE_API SProgressBarEx : public SLeafWidget
{

public:
    SLATE_BEGIN_ARGS(SProgressBarEx)
        : _Style( nullptr )
        , _BarFillType(EProgressBarExFillType::LeftToRight)
        , _Percent( TOptional<float>() )
        , _FillColorAndOpacity( FLinearColor::White )
        , _BorderPadding( FVector2D(1,0) )
        , _BackgroundImage(&FCoreStyle::Get().GetWidgetStyle<FProgressBarStyle>("ProgressBar").BackgroundImage)
        , _IncreaseImage(&FCoreStyle::Get().GetWidgetStyle<FProgressBarStyle>("ProgressBar").FillImage)
        , _DecreaseImage(&FCoreStyle::Get().GetWidgetStyle<FProgressBarStyle>("ProgressBar").FillImage)
        , _FillImage(&FCoreStyle::Get().GetWidgetStyle<FProgressBarStyle>("ProgressBar").FillImage)
        , _MarqueeImage(&FCoreStyle::Get().GetWidgetStyle<FProgressBarStyle>("ProgressBar").MarqueeImage)
        , _RefreshRate(2.0f)
        {}

        /** Style used for the progress bar */
        SLATE_STYLE_ARGUMENT( FProgressBarExStyle, Style )

        /** Defines if this progress bar fills Left to right or right to left*/
        SLATE_ARGUMENT( EProgressBarExFillType::Type, BarFillType )

        /** Used to determine the fill position of the progress bar ranging 0..1 */
        SLATE_ATTRIBUTE( TOptional<float>, Percent )

        /** Fill Color and Opacity */
        SLATE_ATTRIBUTE( FSlateColor, FillColorAndOpacity )

        /** Border Padding around fill bar */
        SLATE_ATTRIBUTE( FVector2D, BorderPadding )
    
        /** The brush to use as the background of the progress bar */
        SLATE_ARGUMENT(const FSlateBrush*, BackgroundImage)

        /** The brush to use as the increase image of the progress bar */
        SLATE_ARGUMENT(const FSlateBrush*, IncreaseImage)

        /** The brush to use as the decrease image of the progress bar */
        SLATE_ARGUMENT(const FSlateBrush*, DecreaseImage)
    
        /** The brush to use as the fill image */
        SLATE_ARGUMENT(const FSlateBrush*, FillImage)
    
        /** The brush to use as the marquee image */
        SLATE_ARGUMENT(const FSlateBrush*, MarqueeImage)

        /** Rate at which this widget is ticked when sleeping in seconds */
        SLATE_ARGUMENT(float, RefreshRate)

    SLATE_END_ARGS()

    /**
     * Construct the widget
     * 
     * @param InArgs   A declaration from which to construct the widget
     */
    void Construct(const FArguments& InArgs);

    /** Paint Widget */
    virtual int32 OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const override;
    virtual FVector2D ComputeDesiredSize(float) const override;
    virtual bool ComputeVolatility() const override;

    /** See attribute Percent */
    void SetPercent(TAttribute< TOptional<float> > InPercent);

    /** See attribute Style */
    void SetStyle(const FProgressBarExStyle* InStyle);

    /** See attribute BarFillType */
    void SetBarFillType(EProgressBarExFillType::Type InBarFillType);
    
    /** See attribute SetFillColorAndOpacity */
    void SetFillColorAndOpacity(TAttribute< FSlateColor > InFillColorAndOpacity);
    
    /** See attribute BorderPadding */
    void SetBorderPadding(TAttribute< FVector2D > InBorderPadding);
    
    /** See attribute BackgroundImage */
    void SetBackgroundImage(const FSlateBrush* InBackgroundImage);

    /** See attribute IncreaseImage */
    void SetIncreaseImage(const FSlateBrush* InIncreaseImage);

    /** See attribute IncreaseImage */
    void SetDecreaseImage(const FSlateBrush* InDecreaseImage);
    
    /** See attribute FillImage */
    void SetFillImage(const FSlateBrush* InFillImage);
    
    /** See attribute MarqueeImage */
    void SetMarqueeImage(const FSlateBrush* InMarqueeImage);

private:

    /** Controls the speed at which the widget is ticked when in slate sleep mode */
    void SetActiveTimerTickRate(float TickRate);

    /** Widgets active tick */
    EActiveTimerReturnType ActiveTick(double InCurrentTime, float InDeltaTime);

    /** Gets the current background image. */
    const FSlateBrush* GetBackgroundImage() const;

    /** Gets the current increase image */
    const FSlateBrush* GetIncreaseImage() const;

    /** Gets the current decrease image */
    const FSlateBrush* GetDecreaseImage() const;

    /** Gets the current fill image */
    const FSlateBrush* GetFillImage() const;

    /** Gets the current marquee image */
    const FSlateBrush* GetMarqueeImage() const;


private:

    /** The style of the progress bar */
    const FProgressBarExStyle* Style;

    /** The text displayed over the progress bar */
    TAttribute< TOptional<float> > CurrentPercent;
    TAttribute< TOptional<float> > TargetPercent;
    TAttribute< TOptional<float> > MiddlePercent;

    /** The fill type for the progress bar */
    EProgressBarExFillType::Type BarFillType;

    /** Background image to use for the progress bar */
    const FSlateBrush* BackgroundImage;

    /** Increase image to use for the progress bar */
    const FSlateBrush* IncreaseImage;

    /** Decrease image to use for the progress bar */
    const FSlateBrush* DecreaseImage;

    /** Foreground image to use for the progress bar */
    const FSlateBrush* FillImage;

    /** Image to use for marquee mode */
    const FSlateBrush* MarqueeImage;

    /** Value to drive progress bar animation */
    float SpeedRate;

    /** Fill Color and Opacity */
    TAttribute<FSlateColor> FillColorAndOpacity;

    /** Border Padding */
    TAttribute<FVector2D> BorderPadding;

    /** Value to drive progress bar animation */
    float MarqueeOffset;

    /** Reference to the widgets current active timer */
    TWeakPtr<FActiveTimerHandle> ActiveTimerHandle;

    /** Rate at which the widget is currently ticked when slate sleep mode is active */
    float CurrentTickRate;

    /** The slowest that this widget can tick when in slate sleep mode */
    float MinimumTickRate;
};

  • SProgressBarEx.cpp
// Fill out your copyright notice in the Description page of Project Settings.

#include "TestMobile.h"
#include "SProgressBarEx.h"

void SProgressBarEx::Construct(const FArguments& InArgs)
{
    check(InArgs._BackgroundImage);
    check(InArgs._IncreaseImage);
    check(InArgs._DecreaseImage);
    check(InArgs._FillImage);
    check(InArgs._MarqueeImage);


    MarqueeOffset = 0.0f;
    Style = InArgs._Style;

    
    TAttribute< TOptional<float> > Percent = InArgs._Percent.Get().IsSet() ? InArgs._Percent : 0.5f;
    SetPercent(Percent);

    SpeedRate = 30.0f;

    BarFillType = InArgs._BarFillType;
    BackgroundImage = InArgs._BackgroundImage;
    IncreaseImage = InArgs._IncreaseImage;
    DecreaseImage = InArgs._DecreaseImage;
    FillImage = InArgs._FillImage;
    MarqueeImage = InArgs._MarqueeImage;

    FillColorAndOpacity = InArgs._FillColorAndOpacity;
    BorderPadding = InArgs._BorderPadding;

    CurrentTickRate = 0.0f;
    MinimumTickRate = InArgs._RefreshRate;

    ActiveTimerHandle = RegisterActiveTimer(CurrentTickRate, FWidgetActiveTimerDelegate::CreateSP(this, &SProgressBarEx::ActiveTick));
}


void SProgressBarEx::SetPercent(TAttribute< TOptional<float> > InPercent)
{
    if (!TargetPercent.IdenticalTo(InPercent))
    {
        CurrentPercent = MiddlePercent = TargetPercent = InPercent;
        Invalidate(EInvalidateWidget::LayoutAndVolatility);
    }
}


void SProgressBarEx::SetStyle(const FProgressBarExStyle* InStyle)
{
    Style = InStyle;

    if (Style == nullptr)
    {
        FArguments Defaults;
        Style = Defaults._Style;
    }

    check(Style);

    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetBarFillType(EProgressBarExFillType::Type InBarFillType)
{
    BarFillType = InBarFillType;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetFillColorAndOpacity(TAttribute< FSlateColor > InFillColorAndOpacity)
{
    FillColorAndOpacity = InFillColorAndOpacity;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetBorderPadding(TAttribute< FVector2D > InBorderPadding)
{
    BorderPadding = InBorderPadding;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetBackgroundImage(const FSlateBrush* InBackgroundImage)
{
    BackgroundImage = InBackgroundImage;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetIncreaseImage(const FSlateBrush* InIncreaseImage)
{
    IncreaseImage = InIncreaseImage;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetDecreaseImage(const FSlateBrush* InDecreaseImage)
{
    DecreaseImage = InDecreaseImage;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetFillImage(const FSlateBrush* InFillImage)
{
    FillImage = InFillImage;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetMarqueeImage(const FSlateBrush* InMarqueeImage)
{
    MarqueeImage = InMarqueeImage;
    Invalidate(EInvalidateWidget::Layout);
}


const FSlateBrush* SProgressBarEx::GetBackgroundImage() const
{
    return &Style->BackgroundImage ? &Style->BackgroundImage : BackgroundImage;
}


const FSlateBrush* SProgressBarEx::GetIncreaseImage() const
{
    return &Style->IncreaseImage ? &Style->IncreaseImage : IncreaseImage;
}


const FSlateBrush* SProgressBarEx::GetDecreaseImage() const
{
    return &Style->DecreaseImage ? &Style->DecreaseImage : DecreaseImage;
}


const FSlateBrush* SProgressBarEx::GetFillImage() const
{
    return &Style->FillImage ? &Style->FillImage : FillImage;
}


const FSlateBrush* SProgressBarEx::GetMarqueeImage() const
{
    return &Style->MarqueeImage ? &Style->MarqueeImage : MarqueeImage;
}


int32 SProgressBarEx::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
{
    // Used to track the layer ID we will return.
    int32 RetLayerId = LayerId;

    bool bEnabled = ShouldBeEnabled( bParentEnabled );
    const ESlateDrawEffect::Type DrawEffects = bEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect;

    const FSlateBrush* CurrentFillImage = GetFillImage();
    const FLinearColor FillColorAndOpacitySRGB(InWidgetStyle.GetColorAndOpacityTint() * FillColorAndOpacity.Get().GetColor(InWidgetStyle) * CurrentFillImage->GetTint(InWidgetStyle));
    const FLinearColor ColorAndOpacitySRGB = InWidgetStyle.GetColorAndOpacityTint();

    // Paint inside the border only. 
    // Pre-snap the clipping rect to try and reduce common jitter, since the padding is typically only a single pixel.
    FSlateRect SnappedClippingRect = FSlateRect(FMath::RoundToInt(MyClippingRect.Left), FMath::RoundToInt(MyClippingRect.Top), FMath::RoundToInt(MyClippingRect.Right), FMath::RoundToInt(MyClippingRect.Bottom));
    const FSlateRect ForegroundClippingRect = SnappedClippingRect.InsetBy(FMargin(BorderPadding.Get().X, BorderPadding.Get().Y));

    // Paint background image
    const FSlateBrush* CurrentBackgroundImage = GetBackgroundImage();
    FSlateDrawElement::MakeBox(
        OutDrawElements,
        RetLayerId++,
        AllottedGeometry.ToPaintGeometry(),
        CurrentBackgroundImage,
        SnappedClippingRect,
        DrawEffects,
        InWidgetStyle.GetColorAndOpacityTint() * CurrentBackgroundImage->GetTint( InWidgetStyle )
    );

    TOptional<float> TargetPercentFraction = TargetPercent.Get();
    TOptional<float> MiddlePercentFraction = MiddlePercent.Get();
    TOptional<float> CurrentPercentFraction = CurrentPercent.Get();

    if ( TargetPercentFraction.IsSet() && MiddlePercentFraction.IsSet() && CurrentPercentFraction.IsSet() )
    {
        // Get percent value
        float TargetPercentValue = FMath::Clamp(TargetPercentFraction.GetValue(), 0.0f, 1.0f);
        float MiddlePercentValue = FMath::Clamp(MiddlePercentFraction.GetValue(), 0.0f, 1.0f);
        float CurrentPercentValue = FMath::Clamp(CurrentPercentFraction.GetValue(), 0.0f, 1.0f);

        // Get paint order
        const FSlateBrush* TopBrush;
        const FSlateBrush* CenterBrush;
        const FSlateBrush* BottomBrush;
        float TopValue;
        float CenterValue;
        float BottomValue;
       

        TopBrush = GetFillImage();
        TopValue = MiddlePercentValue;
        CenterBrush = GetIncreaseImage();
        CenterValue = TargetPercentValue;
        BottomBrush = GetDecreaseImage();
        BottomValue = CurrentPercentValue;


        

        switch (BarFillType)
        {
        case EProgressBarExFillType::RightToLeft:
            break;
        case EProgressBarExFillType::FillFromCenter:
            break;
        case EProgressBarExFillType::TopToBottom:
            break;
        case EProgressBarExFillType::BottomToTop:
            break;
        case EProgressBarExFillType::LeftToRight:
        default:
            // Draw bottom layer
            FSlateRect ClippedAllotedGeometry = FSlateRect(AllottedGeometry.AbsolutePosition, AllottedGeometry.AbsolutePosition + AllottedGeometry.Size * AllottedGeometry.Scale);
            ClippedAllotedGeometry.Right = ClippedAllotedGeometry.Left + ClippedAllotedGeometry.GetSize().X * BottomValue;
            FSlateDrawElement::MakeBox(
                OutDrawElements,
                RetLayerId++,
                AllottedGeometry.ToPaintGeometry(
                    FVector2D::ZeroVector,
                    FVector2D( AllottedGeometry.Size.X, AllottedGeometry.Size.Y )),
                BottomBrush,
                ForegroundClippingRect.IntersectionWith(ClippedAllotedGeometry),
                DrawEffects,
                FillColorAndOpacitySRGB
                );

            // Draw center layer
            ClippedAllotedGeometry =  FSlateRect(AllottedGeometry.AbsolutePosition, AllottedGeometry.AbsolutePosition + AllottedGeometry.Size * AllottedGeometry.Scale);
            ClippedAllotedGeometry.Right = ClippedAllotedGeometry.Left + ClippedAllotedGeometry.GetSize().X * CenterValue;
            FSlateDrawElement::MakeBox(
                OutDrawElements,
                RetLayerId++,
                AllottedGeometry.ToPaintGeometry(
                    FVector2D::ZeroVector,
                    FVector2D( AllottedGeometry.Size.X, AllottedGeometry.Size.Y )),
                CenterBrush,
                ForegroundClippingRect.IntersectionWith(ClippedAllotedGeometry),
                DrawEffects,
                FillColorAndOpacitySRGB
                );

            // Draw top layer
            ClippedAllotedGeometry =  FSlateRect(AllottedGeometry.AbsolutePosition, AllottedGeometry.AbsolutePosition + AllottedGeometry.Size * AllottedGeometry.Scale);
            ClippedAllotedGeometry.Right = ClippedAllotedGeometry.Left + ClippedAllotedGeometry.GetSize().X * TopValue;
            FSlateDrawElement::MakeBox(
                OutDrawElements,
                RetLayerId++,
                AllottedGeometry.ToPaintGeometry(
                    FVector2D::ZeroVector,
                    FVector2D( AllottedGeometry.Size.X, AllottedGeometry.Size.Y )),
                TopBrush,
                ForegroundClippingRect.IntersectionWith(ClippedAllotedGeometry),
                DrawEffects,
                FillColorAndOpacitySRGB
                );
            break;
        }
    }
    else
    {

    }

    return RetLayerId - 1;
}


FVector2D SProgressBarEx::ComputeDesiredSize(float) const
{
    return GetMarqueeImage()->ImageSize;
}


bool SProgressBarEx::ComputeVolatility() const
{
    return SLeafWidget::ComputeVolatility() || TargetPercent.IsBound();
}


void SProgressBarEx::SetActiveTimerTickRate(float TickRate)
{
    if (CurrentTickRate != TickRate || !ActiveTimerHandle.IsValid())
    {
        CurrentTickRate = TickRate;

        TSharedPtr<FActiveTimerHandle> SharedActiveTimerHandle = ActiveTimerHandle.Pin();
        if (SharedActiveTimerHandle.IsValid())
        {
            UnRegisterActiveTimer(SharedActiveTimerHandle.ToSharedRef());
        }

        ActiveTimerHandle = RegisterActiveTimer(TickRate, FWidgetActiveTimerDelegate::CreateSP(this, &SProgressBarEx::ActiveTick));
    }
}


EActiveTimerReturnType SProgressBarEx::ActiveTick(double InCurrentTime, float InDeltaTime)
{
    MarqueeOffset = InCurrentTime - FMath::FloorToDouble(InCurrentTime);

    TOptional<float> TargetPercentFraction = TargetPercent.Get();
    if (TargetPercentFraction.IsSet())
    {
        SetActiveTimerTickRate(MinimumTickRate);
    }
    else
    {
        SetActiveTimerTickRate(0.0f);
    }

    return EActiveTimerReturnType::Continue;
}

这个是一个多层进度条的Slate控件,紧接着要为他写个Slate样式。

  • ProgressBarExStyle.h
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "SlateWidgetStyleContainerBase.h"
#include "SlateWidgetStyle.h"
#include "SlateBasics.h"
#include "ProgressBarExStyle.generated.h"


/**
 * Represents the appearance of an SProgressBarEx
 */
USTRUCT(BlueprintType)
struct TESTMOBILE_API FProgressBarExStyle : public FSlateWidgetStyle
{
    GENERATED_USTRUCT_BODY()

    FProgressBarExStyle();

    virtual ~FProgressBarExStyle() {}

    virtual void GetResources( TArray< const FSlateBrush* >& OutBrushes ) const override;

    static const FName TypeName;
    virtual const FName GetTypeName() const override { return TypeName; };

    static const FProgressBarExStyle& GetDefault();

    /** Background image to use for the progress bar */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Appearance)
    FSlateBrush BackgroundImage;
    FProgressBarExStyle& SetBackgroundImage( const FSlateBrush& InBackgroundImage ){ BackgroundImage = InBackgroundImage; return *this; }

    /** Increase image to use for the progress bar */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Appearance)
    FSlateBrush IncreaseImage;
    FProgressBarExStyle& SetIncreaseImage( const FSlateBrush& InIncreaseImage ){ IncreaseImage = InIncreaseImage; return *this; }

    /** Decrease image to use for the progress bar */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Appearance)
    FSlateBrush DecreaseImage;
    FProgressBarExStyle& SetDecreaseImage( const FSlateBrush& InDecreaseImage ){ DecreaseImage = InDecreaseImage; return *this; }

    /** Foreground image to use for the progress bar */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Appearance)
    FSlateBrush FillImage;
    FProgressBarExStyle& SetFillImage( const FSlateBrush& InFillImage ){ FillImage = InFillImage; return *this; }

    /** Image to use for marquee mode */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Appearance)
    FSlateBrush MarqueeImage;
    FProgressBarExStyle& SetMarqueeImage( const FSlateBrush& InMarqueeImage ){ MarqueeImage = InMarqueeImage; return *this; }
};
  • ProgressBarExStyle.cpp
// Fill out your copyright notice in the Description page of Project Settings.

#include "TestMobile.h"
#include "ProgressBarExStyle.h"

FProgressBarExStyle::FProgressBarExStyle()
{
}

void FProgressBarExStyle::GetResources( TArray< const FSlateBrush* >& OutBrushes ) const
{
    OutBrushes.Add( &BackgroundImage );
    OutBrushes.Add( &IncreaseImage );
    OutBrushes.Add( &DecreaseImage );
    OutBrushes.Add( &FillImage );
    OutBrushes.Add( &MarqueeImage );
}

const FName FProgressBarExStyle::TypeName( TEXT("FProgressBarExStyle") );

const FProgressBarExStyle& FProgressBarExStyle::GetDefault()
{
    static FProgressBarExStyle Default;
    return Default;
}

到此我们就结束了Slate控件的编写,只是写了个基本的多层进度条。


添加到UMG编辑器中

首先需要给样式加上一个基础容器,并且要反射给UMG的编辑器

  • ProgressExWidgetStyle.h
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "Styling/SlateWidgetStyleContainerBase.h"
#include "UI/Slate/ProgressBarExStyle.h"
#include "ProgressExWidgetStyle.generated.h"

/**
 * 
 */
UCLASS(BlueprintType, hidecategories=Object, MinimalAPI)
class UProgressExWidgetStyle : public USlateWidgetStyleContainerBase
{
    GENERATED_BODY()

public:

    /** The actual data describing the button's appearance. */
    UPROPERTY(Category="Style", EditAnywhere, BlueprintReadWrite, meta=(ShowOnlyInnerProperties))
    FProgressBarExStyle ProgressBarExStyle;
    
    virtual const struct FSlateWidgetStyle* const GetStyle() const override
    {
        return static_cast< const struct FSlateWidgetStyle* >( &ProgressBarExStyle );
    }
};

然后要让编辑器能看到我们的Slate控件:

  • ProgressBarEx.h
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "Widget.h"
#include "ProgressExWidgetStyle.h"
#include "UI/Slate/SProgressBarEx.h"
#include "ProgressBarEx.generated.h"

class USlateBrushAsset;

/**
 *  ProgressBarEx
 */
UCLASS()
class TESTMOBILE_API UProgressBarEx : public UWidget
{
    GENERATED_BODY()

public:

    /** The progress bar ex default setting */
    UProgressBarEx(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
    
    /** The progress bar ex style */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Style", meta=( DisplayName="Style" ))
    FProgressBarExStyle WidgetStyle;

    /** Style used for the progress bar */
    UPROPERTY()
    USlateWidgetStyleAsset* Style_DEPRECATED;

    /** The brush to use as the background of the progress bar */
    UPROPERTY()
    USlateBrushAsset* BackgroundImage_DEPRECATED;

    /** The brush to use as the increase image of the progress bar */
    UPROPERTY()
    USlateBrushAsset* IncreaseImage_DEPRECATED;

    /** The brush to use as the decrease image of the progress bar */
    UPROPERTY()
    USlateBrushAsset* DecreaseImage_DEPRECATED;

    /** The brush to use as the fill image */
    UPROPERTY()
    USlateBrushAsset* FillImage_DEPRECATED;

    /** The brush to use as the marquee image */
    UPROPERTY()
    USlateBrushAsset* MarqueeImage_DEPRECATED;

    /** Used to determine the fill position of the progress bar ranging 0..1 */
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Progress, meta=( UIMin = "0", UIMax = "1" ))
    float Percent;

    /** Defines if this progress bar fills Left to right or right to left */
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Progress)
    TEnumAsByte<EProgressBarExFillType::Type> BarFillType;
    
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Progress)
    bool bIsMarquee;

    /** A bindable delegate to allow logic to drive the text of the widget */
    UPROPERTY()
    FGetFloat PercentDelegate;

    /** Fill Color and Opacity */
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Appearance)
    FLinearColor FillColorAndOpacity;

    /** */
    UPROPERTY()
    FGetLinearColor FillColorAndOpacityDelegate;
    
public:
    
    /** Sets the current value of the ProgressBar. */
    UFUNCTION(BlueprintCallable, Category="Progress")
    void SetPercent(float InPercent);

    /** Sets the fill color of the progress bar. */
    UFUNCTION(BlueprintCallable, Category="Progress")
    void SetFillColorAndOpacity(FLinearColor InColor);

    /** Sets the progress bar to show as a marquee. */
    UFUNCTION(BlueprintCallable, Category="Progress")
    void SetIsMarquee(bool InbIsMarquee);

    //TODO UMG Add Set BarFillType.

public:

    //~ Begin UWidget Interface
    virtual void SynchronizeProperties() override;
    //~ End UWidget Interface

    //~ Begin UVisual Interface
    virtual void ReleaseSlateResources(bool bReleaseChildren) override;
    //~ End UVisual Interface

    //~ Begin UObject Interface
    virtual void PostLoad() override;
    //~ End UObject Interface

#if WITH_EDITOR

    //~ Begin UWidget Interface
    virtual const FText GetPaletteCategory() override;
    virtual void OnCreationFromPalette() override;
    //~ End UWidget Interface

#endif

protected:

    /** Native Slate Widget */
    TSharedPtr<SProgressBarEx> MyProgressBar;

    //~ Begin UWidget Interface
    virtual TSharedRef<SWidget> RebuildWidget() override;
    //~ End UWidget Interface
};

  • ProgressBarEx.cpp
// Fill out your copyright notice in the Description page of Project Settings.

#include "TestMobile.h"
#include "UMG.h"
#include "UMGStyle.h"
#include "Slate/SlateBrushAsset.h"
#include "ProgressBarEx.h"

#define LOCTEXT_NAMESPACE "UMG"

/
// UProgressBarEx

UProgressBarEx::UProgressBarEx(const FObjectInitializer& ObjectInitializer /*= FObjectInitializer::Get()*/)
    : Super(ObjectInitializer)
{
    // SProgressBarEx::FArguments SlateDefaults;
    // WidgetStyle = *SlateDefaults._Style;
    // WidgetStyle = FMenuStyles::Get().GetWidgetStyle<FProgressBarExStyle>("HPBarStyle");
    // WidgetStyle.FillImage.TintColor = FLinearColor::White;
    
    BarFillType = EProgressBarExFillType::LeftToRight;
    bIsMarquee = false;
    Percent = 0;
    FillColorAndOpacity = FLinearColor::White;
}


void UProgressBarEx::SetIsMarquee(bool InbIsMarquee)
{
    bIsMarquee = InbIsMarquee;
    if ( MyProgressBar.IsValid() )
    {
        MyProgressBar->SetPercent(bIsMarquee ? TOptional<float>() : Percent);
    }
}

void UProgressBarEx::SetFillColorAndOpacity(FLinearColor Color)
{
    FillColorAndOpacity = Color;
    if (MyProgressBar.IsValid())
    {
        MyProgressBar->SetFillColorAndOpacity(FillColorAndOpacity);
    }
}

void UProgressBarEx::SetPercent(float InPercent)
{
    Percent = InPercent;
    if ( MyProgressBar.IsValid() )
    {
        MyProgressBar->SetPercent(InPercent);
    }
}


void UProgressBarEx::SynchronizeProperties()
{
    Super::SynchronizeProperties();

    TAttribute< TOptional<float> > PercentBinding = OPTIONAL_BINDING_CONVERT(float, Percent, TOptional<float>, ConvertFloatToOptionalFloat);
    TAttribute<FSlateColor> FillColorAndOpacityBinding = OPTIONAL_BINDING(FSlateColor, FillColorAndOpacity);


    // MyProgressBar->SetStyle(&WidgetStyle);

    SProgressBarEx::FArguments SlateDefaults;
    MyProgressBar->SetBackgroundImage(SlateDefaults._BackgroundImage);
    MyProgressBar->SetIncreaseImage(SlateDefaults._IncreaseImage);
    MyProgressBar->SetDecreaseImage(SlateDefaults._DecreaseImage);
    MyProgressBar->SetFillImage(SlateDefaults._FillImage);
    MyProgressBar->SetMarqueeImage(SlateDefaults._MarqueeImage);

    MyProgressBar->SetStyle(&WidgetStyle);

    MyProgressBar->SetBarFillType(BarFillType);
    MyProgressBar->SetPercent(bIsMarquee ? TOptional<float>() : PercentBinding);
    MyProgressBar->SetFillColorAndOpacity(FillColorAndOpacityBinding);
}

void UProgressBarEx::PostLoad()
{
    Super::PostLoad();

    if ( GetLinkerUE4Version() < VER_UE4_DEPRECATE_UMG_STYLE_ASSETS )
    {
        if ( Style_DEPRECATED != nullptr )
        {
            const FProgressBarExStyle* StylePtr = Style_DEPRECATED->GetStyle<FProgressBarExStyle>();
            if ( StylePtr != nullptr )
            {
                WidgetStyle = *StylePtr;
            }

            Style_DEPRECATED = nullptr;
        }

        if ( BackgroundImage_DEPRECATED != nullptr )
        {
            WidgetStyle.BackgroundImage = BackgroundImage_DEPRECATED->Brush;
            BackgroundImage_DEPRECATED = nullptr;
        }

        if ( IncreaseImage_DEPRECATED != nullptr )
        {
            WidgetStyle.IncreaseImage = IncreaseImage_DEPRECATED->Brush;
            IncreaseImage_DEPRECATED = nullptr;
        }

        if ( DecreaseImage_DEPRECATED != nullptr )
        {
            WidgetStyle.DecreaseImage = DecreaseImage_DEPRECATED->Brush;
            DecreaseImage_DEPRECATED = nullptr;
        }

        if ( FillImage_DEPRECATED != nullptr )
        {
            WidgetStyle.FillImage = FillImage_DEPRECATED->Brush;
            FillImage_DEPRECATED = nullptr;
        }

        if ( MarqueeImage_DEPRECATED != nullptr )
        {
            WidgetStyle.MarqueeImage = MarqueeImage_DEPRECATED->Brush;
            MarqueeImage_DEPRECATED = nullptr;
        }
    }
}


void UProgressBarEx::ReleaseSlateResources(bool bReleaseChildren)
{
    Super::ReleaseSlateResources(bReleaseChildren);

    MyProgressBar.Reset();
}


TSharedRef<SWidget> UProgressBarEx::RebuildWidget()
{
    MyProgressBar = SNew(SProgressBarEx)
        .BorderPadding(FVector2D(0.0f, 0.0f));

    return MyProgressBar.ToSharedRef();
}


#if WITH_EDITOR

const FText UProgressBarEx::GetPaletteCategory()
{
    return LOCTEXT("Common", "Common");
}

void UProgressBarEx::OnCreationFromPalette()
{
    FillColorAndOpacity = FLinearColor(0, 0.5f, 1.0f);
}

#endif


/

#undef LOCTEXT_NAMESPACE

其中RebuildWidgetSynchronizeProperties函数很重要。

编译代码后,打开UMG的编辑器,你会发现Common组件下多了一个Progress Bar Ex的控件:

自定义Slate控件

  • 9
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值