I found that in the detail view, such as UMG, when I copied a Slot, it worked, but when I clicked compile, it returned to the state before I copied the attribute. Unless I manually input and change another attribute after copying the Slot, the attribute I copied can be saved.
At the same time, in C++, I found
There is a similar problem with the custom detail view. After I add a button, the execution event will not work. But once I manually rewrite a property, the function just now will be triggered.
.h:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "IDetailCustomization.h"
#include "Components/SplineComponent.h"
#include "ActorComponents/SplineStretchComponent.h"
class EDITOR_API USplineStretchComponentDetails : public IDetailCustomization
{
public:
// 静态方法,用于注册该自定义细节类
static TSharedRef<IDetailCustomization> MakeInstance();
// 覆盖 CustomizeDetails,用于定制细节视图
virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override;
FReply OnResetSplineClicked();
FReply OnSetSplineClicked();
FReply OnGenerateClicked();
FReply OnAverageClicked();
FReply OnPutOnClicked();
FReply OnRecordSplinePointsClicked();
void OnSplineComponentSelected(TSharedPtr<FString> NewSelection, ESelectInfo::Type SelectInfo);
// 生成下拉框项
TSharedRef<SWidget> GenerateSplineComponentWidget(TSharedPtr<FString> InOption);
// 获取当前显示的 SplineComponent 名称
FText GetSelectedSplineComponentText() const;
FReply OnSetHeightClicked();
TArray<TSharedPtr<FString>> SplineComponentOptions;
TArray<USplineComponent*> SplineComponents;
USplineStretchComponent* SplineStretchComponent;
// 下拉框
TSharedPtr<SComboBox<TSharedPtr<FString>>> SplineComponentComboBox;
// 显示文本
TSharedPtr<STextBlock> SplineComponentTextBlock;
TSharedPtr<STextBlock> ResetSplineTextBlock;
TSharedPtr<SButton> SetSplineButton;
TSharedPtr<SButton> ResetSplineButton;
TSharedPtr<SButton> GenerateButton;
TSharedPtr<SButton> AverageButton;
TSharedPtr<SButton> PutOnButton;
TSharedPtr<SButton>RecordSplinePointsButton;
TSharedPtr<SButton>SetHeightButton;
};
.cpp:
// Fill out your copyright notice in the Description page of Project Settings.
#include "Details/SplineStretchComponentDetails.h"
#include "DetailLayoutBuilder.h"
#include "DetailCategoryBuilder.h"
#include "Widgets/Text/STextBlock.h"
#include "Widgets/Input/SButton.h"
#include "IDetailChildrenBuilder.h"
#include "Widgets/Input/SButton.h"
#include "DetailWidgetRow.h"
#define LOCTEXT_NAMESPACE "FSplineStretchComponentDetails"
TSharedRef<IDetailCustomization> USplineStretchComponentDetails::MakeInstance()
{
// 创建一个实例并返回
return MakeShareable(new USplineStretchComponentDetails);
}
void USplineStretchComponentDetails::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
{
IDetailCategoryBuilder& Category = DetailBuilder.EditCategory("Spline");
// 清空数组
SplineComponents.Empty();
SplineComponentOptions.Empty();
// 重置指针
SplineStretchComponent = nullptr;
SplineComponentComboBox.Reset();
SplineComponentTextBlock.Reset();
ResetSplineTextBlock.Reset();
PutOnButton.Reset();
ResetSplineButton.Reset();
// 获取正在定制的对象(即当前正在打开的 USplineStretchComponent)
TArray<TWeakObjectPtr<UObject>> Objects;
DetailBuilder.GetObjectsBeingCustomized(Objects);
if (Objects.Num() > 0)
{
SplineStretchComponent = Cast<USplineStretchComponent>(Objects[0].Get());
if (!SplineStretchComponent)
{
UE_LOG(LogTemp, Warning, TEXT("Failed to cast object to USplineStretchComponent."));
return;
}
if (SplineStretchComponent && SplineStretchComponent->SelectedActor != nullptr)
{
SplineStretchComponent->SelectedActor->GetComponents(SplineComponents);
SplineComponentOptions.Add(MakeShareable(new FString("None"))); // 第一个选项为 None
for (USplineComponent* SplineComponent : SplineComponents)
{
if (SplineComponent)
{
SplineComponentOptions.Add(MakeShareable(new FString(SplineComponent->GetName())));
}
}
// 当前选中的 SplineComponent
/* TSharedPtr<FString> CurrentlySelectedOption = MakeShareable(new FString("None"));
if (!SplineStretchComponent->SplineComponentName.IsEmpty())
{
CurrentlySelectedOption = MakeShareable(new FString(SplineStretchComponent->SplineComponentName));
}*/
// 创建文本框和下拉框
SplineComponentTextBlock = SNew(STextBlock)
.Text(LOCTEXT("SelectSplineComponent", "Spline Component"));
SplineComponentComboBox = SNew(SComboBox<TSharedPtr<FString>>)
.OptionsSource(&SplineComponentOptions)
//.InitiallySelectedItem(CurrentlySelectedOption)
.OnGenerateWidget(this, &USplineStretchComponentDetails::GenerateSplineComponentWidget)
.OnSelectionChanged(this, &USplineStretchComponentDetails::OnSplineComponentSelected)
.Content()
[
SNew(STextBlock)
.Text(this, &USplineStretchComponentDetails::GetSelectedSplineComponentText)
];
// 添加下拉框到细节面板
Category.AddCustomRow(LOCTEXT("SplineComponent", "Spline Component"))
.NameContent()
[
SplineComponentTextBlock.ToSharedRef()
]
.ValueContent()
[
SplineComponentComboBox.ToSharedRef()
];
// 创建 SetSpline 按钮
TSharedPtr<STextBlock> SetSplineTextBlock = SNew(STextBlock)
.Text(LOCTEXT("SetSplineLabel", "Set Spline"));
SetSplineButton = SNew(SButton)
.Text(LOCTEXT("SetSplineButton", "Set Spline"))
.HAlign(HAlign_Center)
.OnClicked(this, &USplineStretchComponentDetails::OnSetSplineClicked);
// 添加 Set Spline 按钮到细节面板
Category.AddCustomRow(LOCTEXT("SetSpline", "Set Spline"))
.NameContent()
[
SetSplineTextBlock.ToSharedRef()
]
.ValueContent()
[
SetSplineButton.ToSharedRef()
];
TSharedPtr<STextBlock> GenerateTextBlock = SNew(STextBlock)
.Text(LOCTEXT("GenerateLabel", "Generate"));
GenerateButton = SNew(SButton)
.Text(LOCTEXT("GenerateButton", "Generate"))
.HAlign(HAlign_Center)
.OnClicked(this, &USplineStretchComponentDetails::OnGenerateClicked);
// 添加 Generate 按钮到细节面板
Category.AddCustomRow(LOCTEXT("Generate", "Generate"))
.NameContent()
[
GenerateTextBlock.ToSharedRef()
]
.ValueContent()
[
GenerateButton.ToSharedRef()
];
// 创建 Average 按钮
TSharedPtr<STextBlock> AverageTextBlock = SNew(STextBlock)
.Text(LOCTEXT("AverageLabel", "Average"));
AverageButton = SNew(SButton)
.Text(LOCTEXT("AverageButton", "Average"))
.HAlign(HAlign_Center)
.OnClicked(this, &USplineStretchComponentDetails::OnAverageClicked);
// 添加 Average 按钮到细节面板
Category.AddCustomRow(LOCTEXT("Average", "Average"))
.NameContent()
[
AverageTextBlock.ToSharedRef()
]
.ValueContent()
[
AverageButton.ToSharedRef()
];
// 创建 Put On 按钮
TSharedPtr<STextBlock> PutOnTextBlock = SNew(STextBlock)
.Text(LOCTEXT("PutOnLabel", "Put On"));
PutOnButton = SNew(SButton)
.Text(LOCTEXT("PutOnButton", "Put On"))
.HAlign(HAlign_Center)
.OnClicked(this, &USplineStretchComponentDetails::OnPutOnClicked);
// 添加按钮到细节面板
Category.AddCustomRow(LOCTEXT("PutOn", "Put On"))
.NameContent()
[
PutOnTextBlock.ToSharedRef()
]
.ValueContent()
[
PutOnButton.ToSharedRef()
];
// 创建 Record Spline Points 按钮
TSharedPtr<STextBlock> RecordTextBlock = SNew(STextBlock)
.Text(LOCTEXT("RecordSplinePointsLabel", "Record Spline Points"));
RecordSplinePointsButton = SNew(SButton)
.Text(LOCTEXT("RecordButton", "Record Spline Points"))
.HAlign(HAlign_Center)
.OnClicked(this, &USplineStretchComponentDetails::OnRecordSplinePointsClicked);
// 添加 Record Spline Points 按钮到细节面板
Category.AddCustomRow(LOCTEXT("RecordSplinePoints", "Record Spline Points"))
.NameContent()
[
RecordTextBlock.ToSharedRef()
]
.ValueContent()
[
RecordSplinePointsButton.ToSharedRef()
];
TSharedPtr<STextBlock> SetHeightTextBlock = SNew(STextBlock)
.Text(LOCTEXT("SetHeightLabel", "Set Height"));
SetHeightButton = SNew(SButton)
.Text(LOCTEXT("SetHeightButton", "Set Height"))
.HAlign(HAlign_Center)
.OnClicked(this, &USplineStretchComponentDetails::OnSetHeightClicked);
// 添加 Set Height 按钮到细节面板
Category.AddCustomRow(LOCTEXT("SetHeight", "Set Height"))
.NameContent()
[
SetHeightTextBlock.ToSharedRef()
]
.ValueContent()
[
SetHeightButton.ToSharedRef()
];
}
}
}
FReply USplineStretchComponentDetails::OnResetSplineClicked()
{
if (SplineStretchComponent)
{
SplineStretchComponent->ResetSpline();
}
return FReply::Handled();
}
FReply USplineStretchComponentDetails::OnSetSplineClicked()
{
if (!SplineStretchComponent)
return FReply::Handled();
TSharedPtr<FString> NewSelection = SplineComponentComboBox->GetSelectedItem();
if (!NewSelection.IsValid())
{
UE_LOG(LogTemp, Warning, TEXT("NewSelection is nullptr."));
return FReply::Handled();
}
else
{
if (*NewSelection == "None")
{
SplineStretchComponent->SplineComponent = nullptr;
}
else
{
// 遍历找到与名称匹配的 SplineComponent
for (UActorComponent* Component : SplineStretchComponent->SelectedActor->GetComponents())
{
// 尝试将 Component 转换为 USplineComponent
if (USplineComponent* SplineComponent = Cast<USplineComponent>(Component))
{
if (SplineComponent && SplineComponent->GetName() == *NewSelection)
{
SplineStretchComponent->SplineComponent = SplineComponent;
SplineStretchComponent->SplineComponentName = SplineComponent->GetName();
break;
}
}
}
}
}
return FReply::Handled();
}
FReply USplineStretchComponentDetails::OnGenerateClicked()
{
if (!SplineStretchComponent)
return FReply::Handled();
SplineStretchComponent->UpdateSplineFromDataTable();
return FReply::Handled();
}
FReply USplineStretchComponentDetails::OnAverageClicked()
{
if (!SplineStretchComponent)
return FReply::Handled();
SplineStretchComponent->AverageResetPoint();
return FReply::Handled();
}
FReply USplineStretchComponentDetails::OnPutOnClicked()
{
if (!SplineStretchComponent)
return FReply::Handled();
SplineStretchComponent->PutOn();
return FReply::Handled();
}
FReply USplineStretchComponentDetails::OnRecordSplinePointsClicked()
{
if (!SplineStretchComponent || !SplineStretchComponent->SplineComponent)
{
UE_LOG(LogTemp, Warning, TEXT("Spline component is not valid."));
return FReply::Handled();
}
// 清空之前记录的点
SplineStretchComponent->SplinePointsPositions.Empty();
// 遍历样条线的所有点并记录位置
int32 NumPoints = SplineStretchComponent->SplineComponent->GetNumberOfSplinePoints();
for (int32 i = 0; i < NumPoints; ++i)
{
FVector PointLocation = SplineStretchComponent->SplineComponent->GetLocationAtSplinePoint(i, ESplineCoordinateSpace::World);
SplineStretchComponent->SplinePointsPositions.Add(PointLocation);
}
UE_LOG(LogTemp, Log, TEXT("Recorded %d spline points."), SplineStretchComponent->SplinePointsPositions.Num());
return FReply::Handled();
}
void USplineStretchComponentDetails::OnSplineComponentSelected(TSharedPtr<FString> NewSelection, ESelectInfo::Type SelectInfo)
{
if (NewSelection.IsValid())
{
SplineStretchComponent->SplineComponentName = *NewSelection;
}
}
TSharedRef<SWidget> USplineStretchComponentDetails::GenerateSplineComponentWidget(TSharedPtr<FString> InOption)
{
return SNew(STextBlock).Text(FText::FromString(*InOption));
}
FText USplineStretchComponentDetails::GetSelectedSplineComponentText() const
{
TSharedPtr<FString> SelectedItem = SplineComponentComboBox->GetSelectedItem();
// 如果选项有效,返回选中的文本
if (SelectedItem.IsValid())
{
return FText::FromString(*SelectedItem);
}
if (!SplineStretchComponent->SplineComponentName.IsEmpty())
{
return FText::FromString(SplineStretchComponent->SplineComponentName);
}
else
{
return FText::FromString(TEXT("None"));
}
}
FReply USplineStretchComponentDetails::OnSetHeightClicked()
{
/* if (!SplineStretchComponent || !SplineStretchComponent->SplineComponent)
{
UE_LOG(LogTemp, Warning, TEXT("Spline component is not valid."));
return FReply::Handled();
}
SplineStretchComponent->SetHeight()*/;
return FReply::Handled();
}
#undef LOCTEXT_NAMESPACE