Adding an Editor Actor Picker via Slate

I am using the following Slate pattern to create a drop down editor menu where I can pick an actor in the scene. While I am able to pick the actor from the dropdown menu, the tooltip on the dropdown menu claims it cannot find the selected object.

SNew(SObjectPropertyEntryBox)
.AllowedClass(AActor::StaticClass())
.ObjectPath(this, &SMapSnapper::GetFixedMapString)
.OnObjectChanged(this, &SMapSnapper::FixedMapOnChanged)
  • SMapSnapper::FixedMapOnChanged
    sets a member variable to the selected actor. This member variable gets set correctly even with the displayed error.

    SMapSnapper::GetFixedMapString
    returns the aforementioned member variable’s path using GetObjectPath().

I don’t receive the error if the AllowedClass is something other than AActor, i.e., assets, materials, things that are not in the scene.

Perhaps SObjectPropertyEntryBox is not the right tool for this. Also, the broken path SObjectPropertyEntryBox claims is Game/FirstPersonCpp/Maps/FirstPersonExampleMap.FirstPersonExampleMap:PersistentLevel.ObjectName
which looks like a perfectly reasonable path to me.

TLDR: Basically I need a slate version of

UPROPERTY(EditAnywhere)
	AActor* ObjectName;

Hey, have you found anything yet? If yes then could you please share your solution?
Thanks.

If this is tied to an existing actor property a simple thing you can do is use the property editor module to create a single property entry e.g

static FName propertyEditorName("PropertyEditor");
FPropertyEditorModule& propertyModule = FModuleManager::GetModuleChecked<FPropertyEditorModule(propertyEditorName);

FSinglePropertyParams propParams;

TSharedRef<SVerticalBox> box = SNew(SVerticalBox)
						+ SVerticalBox::Slot().AutoHeight().HAlign(HAlign_Fill).Padding(2)
						[
							propertyModule.CreateSingleProperty(YOUR_OBJECT_INSTANCE, GET_MEMBER_NAME_CHECKED(YOUR_CLASS_NAME,
								YOUR_VARIABLE_NAME), propParams).ToSharedRef()
						]

Alternatively there’s the PropertyCustomizationHelpers class (where you already found SObjectPropertyEntryBox I suspect) and it has the functions MakeActorPickerWithMenu for example, which I think more directly suit what you seem to need.

Just remember both of these examples need you to include the PropertyEditor in your editorbuild.cs

// in YourWindow.h
class xxx YourWindow : public SCompoundWidget
{

// other code...

FString ActorPath;
FString HandleActorPath() const {return ActorPath;}
void OnActorChanged(const FAssetData& InAsset) {ActorPath = InAsset.GetObjectPathString();}
}

// in YourWindow.cpp
SNew(SObjectPropertyEntryBox)
		.AllowedClass(AActor::StaticClass())
		.AllowClear(true)
		.DisplayBrowse(true)
		.DisplayUseSelected(true)
		.ObjectPath(this, &YourWindow::HandleActorPath)
		.OnObjectChanged(this, &YourWindow::OnActorChanged);
2 Likes

This helped lead me to the solution to my problem. I was trying to make an Actor Picker that filtered on whether the actor had a specific ActorComponent.

I found a guide on filtering here: Creating Filtered Object Pickers. But that didn’t allow me to pick actors in the scene.

Using the code posted by @Shen_Yuju, I was able to modify it to get what I needed:

void FMyWrapperStructCustomization::CustomizeHeader(TSharedRef<IPropertyHandle> StructPropertyHandle, class FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils)
{
	TSharedPtr<IPropertyHandle> MyProperty = StructPropertyHandle->GetChildHandle(TEXT("MyPropertyName"));

	HeaderRow.NameContent()
		[
			StructPropertyHandle->CreatePropertyNameWidget()
		]
		.ValueContent()
		[
			SNew(SObjectPropertyEntryBox)
				.AllowedClass(AActor::StaticClass())
				.AllowClear(true)
				.DisplayBrowse(true)
				.DisplayUseSelected(true)
				.PropertyHandle(MyProperty)
				.OnShouldFilterActor(FOnShouldFilterActor::CreateRaw(this, &FMyWrapperStructCustomization::OnShouldFilterActor))
		];
}

bool FMyWrapperStructCustomization::OnShouldFilterActor(const AActor* InActor)
{
	auto Component = InActor->GetComponentByClass(UMyActorComponent::StaticClass());
	return Component != nullptr;
}

Thanks @Shen_Yuju! Hope this helps someone in the future!