Responding to property changed events from the editor

2021/01 02 13:01

When a designer changes the properties of an Actor placed in the level, it is often important to show any visual results of that change immediately rather than just when the level is simulated or played. When changes are made using the Details panels, there’s a special event that the editor emits called PostEditChangeProperty, which gives the class instance a chance to respond to the property being edited. This recipe shows you how to handle PostEditChangeProperty for immediate in-editor feedback.

How to do it…

  1. Create a new Actor called PostEditChangePropertyActor based on StaticMeshActor:
  1. Add the following UPROPERTY and function definition to the class:
UCLASS()
class CHAPTER_09_API APostEditChangePropertyActor : public
AStaticMeshActor
{
GENERATED_BODY()

// Sets default values for this actor's properties
APostEditChangePropertyActor();

UPROPERTY(EditAnywhere)
bool ShowStaticMesh = true;

virtual void PostEditChangeProperty(FPropertyChangedEvent&
PropertyChangedEvent) override;


};
  1. Create the class constructor by adding the following code to the PostEditChangePropertyActor.cpp file:
#include "PostEditChangePropertyActor.h"
#include "ConstructorHelpers.h"

APostEditChangePropertyActor::APostEditChangePropertyActor()
{
// Set this actor to call Tick() every frame. You can turn
// this off to improve performance if you don't need it.

PrimaryActorTick.bCanEverTick = true;

auto MeshAsset = ConstructorHelpers::FObjectFinder<UStaticMesh>
(TEXT("StaticMesh'/Engine/BasicShapes/Cone.Cone'"));


UStaticMeshComponent * SM = GetStaticMeshComponent();

if (SM != nullptr)
{
if (MeshAsset.Object != nullptr)
{
SM->SetStaticMesh(MeshAsset.Object);
SM->SetGenerateOverlapEvents(true);
}
SM->SetMobility(EComponentMobility::Movable);
}
}
  1. Implement PostEditChangeProperty:
void APostEditChangePropertyActor::PostEditChangeProperty( FPropertyChangedEvent& PropertyChangedEvent)
{
// Check if property is valid
if (PropertyChangedEvent.Property != nullptr)
{
// Get the name of the changed property
const FName PropertyName(
PropertyChangedEvent.Property->GetFName());

// If the changed property is ShowStaticMesh then we
// will set the visibility of the actor
if (PropertyName == GET_MEMBER_NAME_CHECKED(
APostEditChangePropertyActor, ShowStaticMesh))
{
UStaticMeshComponent * SM = GetStaticMeshComponent();

if (SM != nullptr)
{
SM->SetVisibility(ShowStaticMesh);
}
}
}

// Then call the parent version of this function
Super::PostEditChangeProperty(PropertyChangedEvent);
}
  1. Compile your code and launch the editor.
  2. Drag an instance of your class into the game world and verify that toggling the Boolean value for ShowStaticMesh toggles the visibility of the mesh in the editor viewport:

The location of the Show Static Mesh property

Then, if you ever toggle it off, you’ll see the object disappear, as follows:

How it works…

We create a new Actor based on StaticMeshActor for easy access to a visual representation via the Static Mesh.

UPROPERTY is added to give us a property to change, which causes PostEditChangeProperty events to be triggered.

PostEditChangeProperty is a virtual function that’s defined in Actor.

As a result, we override the function in our class.

Within our class constructor, we initialize our mesh as usual, and set the default state of our bool property to match the visibility of the component it controls.

Inside PostEditChangeProperty, we first check that the property is valid.

Assuming it is, we retrieve the name of the property using GetFName().

FNames are stored internally by the engine as a table of unique values.

Next, we need to use the GET_MEMBER_NAME_CHECKED macro. The macro takes a number of parameters.

The first one is the name of the class to check, while the second parameter is the property to check the class for.

The macro will, at compile-time, verify that the class contains the member specified by name.

We compare the class member name that the macro returns against the name that our property contains.

If they are the same, then we verify that our StaticMeshComponent is initialized correctly.

If it is, we set its visibility to match the value of our ShowStaticMesh Boolean.