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

三.效果

相关推荐
andyweike5 分钟前
Swift
开发语言·ios·swift
纪念 2297 分钟前
C++算法(六)
开发语言·c++·算法
ShineWinsu36 分钟前
对于Qt:QCheckBox常见属性的详细解析
c++·qt·面试·笔试·gui·qcheckbox·多选框
_冷眸_1 小时前
Python 调用大模型 API:最小请求、Base URL 和 401/404 排查
开发语言·人工智能·python
niucloud-admin1 小时前
NIUCLOUD PHP SAAS上门家政使用文档:服务保障
java·开发语言·php
AI的探索之旅1 小时前
97 个 OpenCV 实例(三十七):二维码识别,一张图四个码的陷阱
c++·opencv·计算机视觉
熊猫钓鱼>_>1 小时前
鸿蒙 PC 三方库适配复盘:libfvad 1.0 —— 把 WebRTC VAD 做成能装进采集链路的静态库
服务器·开发语言·华为·harmonyos·openharmony·适配·鸿蒙pc
Ai-_Man2 小时前
Coze扣子还是不可以导出左侧所有对话,只能点进去单条内容导出,方法不对吗?
开发语言·人工智能·ai·小程序·1024程序员节
UIU1142 小时前
P16237 [蓝桥杯 2026 省 B] 应急布线
数据结构·c++·算法·蓝桥杯
raindayinrain2 小时前
c++设计模式
开发语言·c++·设计模式