一.直接上代码
头文件
cpp
#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
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; //值域 + - 2000
for (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; //值域 + - 2000
for (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函数,进行绘画。
三.效果
