UE5 C++ Slate 画曲线

一.直接上代码

头文件

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函数,进行绘画。

三.效果

相关推荐
CryptoRzz8 分钟前
日本股票 API 对接实战指南(实时行情与 IPO 专题)
java·开发语言·python·区块链·maven
yugi9878389 分钟前
基于M序列的直扩信号扩频码生成方法及周期长码直扩信号的MATLAB实现方案
开发语言·matlab
乾元16 分钟前
基于时序数据的异常预测——短期容量与拥塞的提前感知
运维·开发语言·网络·人工智能·python·自动化·运维开发
江上清风山间明月17 分钟前
使用python将markdown文件生成pdf文件
开发语言·python·pdf
j_xxx404_20 分钟前
C++算法入门:二分查找合集(二分查找|在排序数组中查找元素的第一个和最后一个位置)
开发语言·c++
ss27323 分钟前
阻塞队列:ArrayBlockingQueue如何用Lock与Condition实现高效并发控制
开发语言·python
lizz3125 分钟前
C++操作符重载深度解析
java·c++·算法
CodeCraft Studio26 分钟前
Vaadin 25 正式发布:回归标准Java Web,让企业级开发更简单、更高效
java·开发语言·前端·vaadin·java web 框架·纯java前端框架·企业级java ui框架
Shirley~~30 分钟前
PPTist 幻灯片工具栏Toolbar部分
开发语言·前端·javascript
|晴 天|31 分钟前
Promise 与 async/await 错误处理最佳实践指南
开发语言·前端·javascript