UE5 C++ Slate 画曲线
一.直接上代码
头文件
#pragma once#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Rendering/DrawElementTypes.h"
#include "SmoothLineWidget.generated.h"/*** */
UCLASS()
class GWXPJ_API USmoothLineWidget : public UUserWidget
{GENERATED_BODY()
public:UFUNCTION(BlueprintCallable)void SetValues(TArray<float> InValues);
protected:virtual int32 NativePaint(const FPaintArgs& Args,const FGeometry& AllottedGeometry,const FSlateRect& MyCullingRect,FSlateWindowElementList& OutDrawElements,int32 LayerId,const FWidgetStyle& InWidgetStyle,bool bParentEnabled) const;void DrawSmoothedLine(FSlateWindowElementList& OutDrawElement,uint32 LayerId,const FGeometry& InAllottedGeometry,TArray<FVector2D> InPoints,float InThickness,FColor InColor)const;TArray<FVector2D> MultiplyPoint;
};CPP
// Fill out your copyright notice in the Description page of Project Settings.#include "GWXWidget.h"
#include "Components/CanvasPanelSlot.h"void UGWXWidget::SetValues(TArray<float> InValues)
{if (InValues.Num() < 2){return;}MultiplyPoint.Empty();UCanvasPanelSlot* CanvsdPanelSlot = Cast<UCanvasPanelSlot>(this->Slot);if (CanvsdPanelSlot == nullptr)return;float WidgetWidth = CanvsdPanelSlot->GetSize().X;float WidgetHeight = CanvsdPanelSlot->GetSize().Y;float Space = WidgetWidth / (InValues.Num() - 1);float HeightSpace = WidgetHeight / 2000; //值域 + - 2000for (int32 Index = 0; Index < InValues.Num(); Index++) //数据输入{FVector2D KeyPosition(Space * Index, WidgetHeight - InValues[Index]*HeightSpace);MultiplyPoint.Add(KeyPosition);}
}int32 UGWXWidget::NativePaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
{DrawSmoothedLine(OutDrawElements,LayerId,AllottedGeometry,MultiplyPoint,1.0f,FColor::Red);//float Numx = 10; //X轴的取值点数float Numy = 10; //Y轴的取值点数UCanvasPanelSlot* CanvsdPanelSlot = Cast<UCanvasPanelSlot>(this->Slot);if (!CanvsdPanelSlot){return LayerId++;}float WidgetWidth = CanvsdPanelSlot->GetSize().X;float WidgetHeight = CanvsdPanelSlot->GetSize().Y;float Space = WidgetWidth / (Numx);//X 轴刻度for (int32 Index = 0;Index <= Numx;Index++){FVector2D TextPosition = FVector2D(Space *Index,WidgetHeight);FSlateFontInfo SlateFontInfo = FCoreStyle::GetDefaultFontStyle("Regular",10);FSlateDrawElement::MakeText(OutDrawElements,LayerId,AllottedGeometry.ToOffsetPaintGeometry(TextPosition),FText::FromString(FString::FromInt(Index * 10)),SlateFontInfo,ESlateDrawEffect::None,FLinearColor::White);}// Y轴刻度 float HeightSpace = WidgetHeight / 2000*200; //值域 + - 2000for (int32 Index = 0; Index <= Numy; Index++){FVector2D TextPosition = FVector2D(-30,HeightSpace*Index-10);FSlateFontInfo SlateFontInfo = FCoreStyle::GetDefaultFontStyle("Regular", 10);FSlateDrawElement::MakeText(OutDrawElements,LayerId,AllottedGeometry.ToOffsetPaintGeometry(TextPosition),FText::FromString(FString::FromInt((Numy-Index) * 200)),SlateFontInfo,ESlateDrawEffect::None,FLinearColor::White);}return LayerId++;
} //变化void UGWXWidget::DrawSmoothedLine(FSlateWindowElementList& OutDrawElement, uint32 InLayerId, const FGeometry& InAllottedGeometry, TArray<FVector2D> InPoints, float InThickness, FColor InColor) const
{if (InPoints.Num() < 2){return;}FRichCurve* RichCurve = new FRichCurve();for (FVector2D InPoint : InPoints){FKeyHandle KeyHandle = RichCurve->AddKey(InPoint.X, InPoint.Y);RichCurve->SetKeyInterpMode(KeyHandle, ERichCurveInterpMode::RCIM_Cubic);}UCanvasPanelSlot* CanvasPanelSlot = Cast<UCanvasPanelSlot>(this->Slot);if (CanvasPanelSlot == nullptr)return;TArray<FVector2D> ResultPoints;float WidgetWidth = CanvasPanelSlot->GetSize().X;int32 Begin = 0;int32 End = (int32)WidgetWidth;for (int32 X = Begin; X < End; X++){float Y = RichCurve->Eval(X);FVector2D ResultPoint(X, Y);ResultPoints.Add(ResultPoint);}delete RichCurve;FSlateDrawElement::MakeLines(OutDrawElement,InLayerId,InAllottedGeometry.ToPaintGeometry(),ResultPoints,ESlateDrawEffect::None,InColor,true,InThickness);
}
二. 首先我们必须包含 UMG 模块,因为要在C++里继承UserWidget。其次我们需要包好Slate和SlateCore 模块。因为这样才能使用Slate编程里的函数API
三.思路
1.这里我们SetValues用于外部调用。
2.NativePaint更像是一个循环。

这里我们看到。它更是UserWidget里用来画最大LayerID的,当LayerID增加,它就不停刷新。
这里也绘制了X轴,Y轴,使用的是FSlateDrawElement::MakeText
3.将数组两两放入曲线中,得到更顺滑的数组。最终核心的Slate 还是FSlateDrawElement::MakeLines函数,进行绘画。
三.效果

