UE编辑器中Actor属性的展示和修改
一、如何展示actor的属性
查看/修改一个对象的时候,我们都是在编辑器中打开地图,然后选中地图中的一个actor,右侧就会自动出现该actor对应的属性列表。
下面是一个选中一个Actor对象时创建对应更新属性对象的调用链。可以看到,当选中一个Actor对象时,对于该对象的属性遍历是自动进行。由于UE支持C++反射,所以给出一个Actor对象时,就可以遍历这个对象的所有Property。
UE4Editor-PropertyEditor.dll!FPropertyValueImpl::FPropertyValueImpl(TSharedPtr<FPropertyNode,0> InPropertyNode, FNotifyHook * InNotifyHook, TSharedPtr<IPropertyUtilities,0> InPropertyUtilities) 行 48 C++
UE4Editor-PropertyEditor.dll!FPropertyHandleBase::FPropertyHandleBase(TSharedPtr<FPropertyNode,0> PropertyNode, FNotifyHook * NotifyHook, TSharedPtr<IPropertyUtilities,0> PropertyUtilities) 行 2138 C++
[内联框架] UE4Editor-PropertyEditor.dll!FPropertyHandleArray::{ctor}(TSharedRef<FPropertyNode,0>) 行 3298 C++
UE4Editor-PropertyEditor.dll!PropertyEditorHelpers::GetPropertyHandle(TSharedRef<FPropertyNode,0> PropertyNode, FNotifyHook * NotifyHook, TSharedPtr<IPropertyUtilities,0> PropertyUtilities) 行 593 C++
UE4Editor-PropertyEditor.dll!DetailLayoutHelpers::UpdateSinglePropertyMapRecursive(FPropertyNode & InNode, FName CurCategory, FComplexPropertyNode * CurObjectNode, DetailLayoutHelpers::FUpdatePropertyMapArgs & InUpdateArgs) 行 120 C++
UE4Editor-PropertyEditor.dll!DetailLayoutHelpers::UpdateSinglePropertyMapRecursive(FPropertyNode & InNode, FName CurCategory, FComplexPropertyNode * CurObjectNode, DetailLayoutHelpers::FUpdatePropertyMapArgs & InUpdateArgs) 行 64 C++
UE4Editor-PropertyEditor.dll!SDetailsViewBase::UpdateSinglePropertyMap(TSharedPtr<FComplexPropertyNode,0> InRootPropertyNode, FDetailLayoutData & LayoutData, bool bIsExternal) 行 403 C++
UE4Editor-PropertyEditor.dll!SDetailsViewBase::UpdatePropertyMaps() 行 373 C++
UE4Editor-PropertyEditor.dll!SDetailsView::PostSetObject(const TArray<FDetailsViewObjectRoot,TSizedDefaultAllocator<32>> & Roots) 行 870 C++
UE4Editor-PropertyEditor.dll!SDetailsView::SetObjectArrayPrivate(const TArray<UObject *,TSizedDefaultAllocator<32>> & InObjects) 行 650 C++
UE4Editor-PropertyEditor.dll!SDetailsView::SetObjects(const TArray<UObject *,TSizedDefaultAllocator<32>> & InObjects, bool bForceRefresh, bool bOverrideLock) 行 416 C++
UE4Editor-LevelEditor.dll!SActorDetails::SetObjects(const TArray<UObject *,TSizedDefaultAllocator<32>> & InObjects, bool bForceRefresh) 行 239 C++
UE4Editor-LevelEditor.dll!SLevelEditor::OnActorSelectionChanged(const TArray<UObject *,TSizedDefaultAllocator<32>> & NewSelection, bool bForceRefresh) 行 1753 C++
[内联框架] UE4Editor-LevelEditor.dll!Invoke(void(SLevelEditor::*)(const TArray<UObject *,TSizedDefaultAllocator<32>> &, bool)) 行 65 C++
[内联框架] UE4Editor-LevelEditor.dll!UE4Tuple_Private::TTupleBase<TIntegerSequence<unsigned int>>::ApplyAfter(void(SLevelEditor::*)(const TArray<UObject *,TSizedDefaultAllocator<32>> &, bool) &) 行 299 C++
UE4Editor-LevelEditor.dll!TBaseSPMethodDelegateInstance<0,SLevelEditor,0,void __cdecl(TArray<UObject *,TSizedDefaultAllocator<32>> const &,bool),FDefaultDelegateUserPolicy>::ExecuteIfSafe(const TArray<UObject *,TSizedDefaultAllocator<32>> & <Params_0>, bool <Params_1>) 行 307 C++
[内联框架] UE4Editor-LevelEditor.dll!TMulticastDelegate<void __cdecl(TArray<UObject *,TSizedDefaultAllocator<32>> const &,bool),FDefaultDelegateUserPolicy>::Broadcast(const TArray<UObject *,TSizedDefaultAllocator<32>> &) 行 955 C++
UE4Editor-LevelEditor.dll!FLevelEditorModule::BroadcastActorSelectionChanged(const TArray<UObject *,TSizedDefaultAllocator<32>> & NewSelection, bool bForceRefresh) 行 447 C++
UE4Editor-UnrealEd.dll!UUnrealEdEngine::UpdateFloatingPropertyWindowsFromActorList(const TArray<UObject *,TSizedDefaultAllocator<32>> & ActorList, bool bForceRefresh) 行 64 C++
UE4Editor-UnrealEd.dll!UUnrealEdEngine::UpdateFloatingPropertyWindows(bool bForceRefresh) 行 55 C++
UE4Editor-UnrealEd.dll!UUnrealEdEngine::NoteSelectionChange(bool bNotify) 行 417 C++
UE4Editor-SceneOutliner.dll!SceneOutliner::SSceneOutliner::OnOutlinerTreeSelectionChanged(TSharedPtr<SceneOutliner::ITreeItem,0> TreeItem, ESelectInfo::Type SelectInfo) 行 3367 C++
[内联框架] UE4Editor-SceneOutliner.dll!Invoke(void(SceneOutliner::SSceneOutliner::*)(TSharedPtr<SceneOutliner::ITreeItem,0>, ESelectInfo::Type)) 行 65 C++
[内联框架] UE4Editor-SceneOutliner.dll!UE4Tuple_Private::TTupleBase<TIntegerSequence<unsigned int>>::ApplyAfter(void(SceneOutliner::SSceneOutliner::*)(TSharedPtr<SceneOutliner::ITreeItem,0>, ESelectInfo::Type) &) 行 299 C++
UE4Editor-SceneOutliner.dll!TBaseSPMethodDelegateInstance<0,SceneOutliner::SSceneOutliner,0,void __cdecl(TSharedPtr<SceneOutliner::ITreeItem,0>,enum ESelectInfo::Type),FDefaultDelegateUserPolicy>::ExecuteIfSafe(TSharedPtr<SceneOutliner::ITreeItem,0> <Params_0>, ESelectInfo::Type <Params_1>) 行 307 C++
[内联框架] UE4Editor-SceneOutliner.dll!TDelegate<void __cdecl(TSharedPtr<SceneOutliner::ITreeItem,0>,enum ESelectInfo::Type),FDefaultDelegateUserPolicy>::ExecuteIfBound(TSharedPtr<SceneOutliner::ITreeItem,0>) 行 599 C++
UE4Editor-SceneOutliner.dll!SListView<TSharedPtr<SceneOutliner::ITreeItem,0>>::Private_SignalSelectionChanged(ESelectInfo::Type SelectInfo) 行 947 C++
UE4Editor-SceneOutliner.dll!STreeView<TSharedPtr<SceneOutliner::ITreeItem,0>>::Private_SignalSelectionChanged(ESelectInfo::Type SelectInfo) 行 501 C++
UE4Editor-SceneOutliner.dll!STableRow<TSharedPtr<SceneOutliner::ITreeItem,0>>::OnMouseButtonUp(const FGeometry & MyGeometry, const FPointerEvent & MouseEvent) 行 617 C++
UE4Editor-SceneOutliner.dll!SceneOutliner::SSceneOutlinerTreeRow::OnMouseButtonUp(const FGeometry & MyGeometry, const FPointerEvent & MouseEvent) 行 263 C++
[内联框架] UE4Editor-Slate.dll!FSlateApplication::RoutePointerUpEvent::__l8::<lambda_345a5758a2260d3d061d4759ff6c6cee>::operator()(const FArrangedWidget &) 行 4829 C++
UE4Editor-Slate.dll!FEventRouter::Route<FReply,FEventRouter::FToLeafmostPolicy,FPointerEvent,<lambda_345a5758a2260d3d061d4759ff6c6cee>>(FSlateApplication * ThisApplication, FEventRouter::FToLeafmostPolicy RoutingPolicy, FPointerEvent EventCopy, const FSlateApplication::RoutePointerUpEvent::__l8::<lambda_345a5758a2260d3d061d4759ff6c6cee> & Lambda, ESlateDebuggingInputEvent DebuggingInputEvent) 行 378 C++
UE4Editor-Slate.dll!FSlateApplication::RoutePointerUpEvent(const FWidgetPath & WidgetsUnderPointer, const FPointerEvent & PointerEvent) 行 4815 C++
UE4Editor-Slate.dll!FSlateApplication::ProcessMouseButtonUpEvent(const FPointerEvent & MouseEvent) 行 5356 C++
二、哪些内容会被展示
这里遍历的是一个对象的所有属性(Property)
void SDetailsViewBase::UpdatePropertyMaps()
{
……
for(int32 RootNodeIndex = 0; RootNodeIndex < RootPropertyNodes.Num(); ++RootNodeIndex)
{
FDetailLayoutData& LayoutData = DetailLayouts[RootNodeIndex];
UpdateSinglePropertyMap(RootPropertyNodes[RootNodeIndex], LayoutData, false);
}
……
}
三、Property从哪里来
例如一个AActor声明中的UpdateOverlapsMethodDuringLevelStreaming变量,在C++声明前面添加了UPROPERTY,所以UHT会为该对象生成对应的Property声明。并且由于声明了它的Category=Collision,所以它在面板中也是展示在Collsion页签分类中。
UCLASS(BlueprintType, Blueprintable, config=Engine, meta=(ShortTooltip="An Actor is an object that can be placed or spawned in the world."))
class ENGINE_API AActor : public UObject
{
……
UPROPERTY(Category=Collision, EditAnywhere)
EActorUpdateOverlapsMethod UpdateOverlapsMethodDuringLevelStreaming;
……
}
四、展示的内容修改后如何更新到内存对象
简单来看,界面中变量修改写回内存对象也是基于Property这个结构来完成,调用这个对象的importXXX接口来修改对象在内存中的值。
UE4Editor-CoreUObject.dll!FByteProperty::ImportText_Internal(const wchar_t * InBuffer, void * Data, int PortFlags, UObject * Parent, FOutputDevice * ErrorText) 行 397 C++
UE4Editor-CoreUObject.dll!FProperty::ImportText(const wchar_t * Buffer, void * Data, int PortFlags, UObject * OwnerObject, FOutputDevice * ErrorText) 行 351 C++
[内联框架] UE4Editor-PropertyEditor.dll!FPropertyTextUtilities::TextToPropertyHelper(const wchar_t * ValueAddress, const FPropertyNode *) 行 63 C++
UE4Editor-PropertyEditor.dll!FPropertyTextUtilities::TextToPropertyHelper(const wchar_t * Buffer, const FPropertyNode * InPropertyNode, const FProperty * Property, const FObjectBaseAddress & ObjectAddress) 行 75 C++
UE4Editor-PropertyEditor.dll!FPropertyValueImpl::ImportText(const TArray<FObjectBaseAddress,TSizedDefaultAllocator<32>> & InObjects, const TArray<FString,TSizedDefaultAllocator<32>> & InValues, FPropertyNode * InPropertyNode, unsigned int Flags) 行 444 C++
UE4Editor-PropertyEditor.dll!FPropertyValueImpl::ImportText(const FString & InValue, FPropertyNode * InPropertyNode, unsigned int Flags) 行 269 C++
UE4Editor-PropertyEditor.dll!FPropertyValueImpl::SetValueAsString(const FString & InValue, unsigned int Flags) 行 796 C++
UE4Editor-PropertyEditor.dll!SPropertyEditorCombo::SendToObjects(const FString & NewValue) 行 255 C++
UE4Editor-PropertyEditor.dll!SPropertyEditorCombo::OnComboSelectionChanged(TSharedPtr<FString,0> NewValue, ESelectInfo::Type SelectInfo) 行 195 C++
[内联框架] UE4Editor-PropertyEditor.dll!Invoke(void(SPropertyEditorCombo::*)(TSharedPtr<FString,0>, ESelectInfo::Type)) 行 65 C++
[内联框架] UE4Editor-PropertyEditor.dll!UE4Tuple_Private::TTupleBase<TIntegerSequence<unsigned int>>::ApplyAfter(void(SPropertyEditorCombo::*)(TSharedPtr<FString,0>, ESelectInfo::Type) &) 行 299 C++
UE4Editor-PropertyEditor.dll!TBaseSPMethodDelegateInstance<0,SPropertyEditorCombo,0,void __cdecl(TSharedPtr<FString,0>,enum ESelectInfo::Type),FDefaultDelegateUserPolicy>::ExecuteIfSafe(TSharedPtr<FString,0> <Params_0>, ESelectInfo::Type <Params_1>) 行 307 C++
[内联框架] UE4Editor-PropertyEditor.dll!TDelegate<void __cdecl(TSharedPtr<FString,0>,enum ESelectInfo::Type),FDefaultDelegateUserPolicy>::ExecuteIfBound(TSharedPtr<FString,0>) 行 599 C++
UE4Editor-PropertyEditor.dll!SPropertyComboBox::OnSelectionChangedInternal(TSharedPtr<FString,0> InSelectedItem, ESelectInfo::Type SelectInfo) 行 123 C++
[内联框架] UE4Editor-PropertyEditor.dll!Invoke(void(SPropertyComboBox::*)(TSharedPtr<FString,0>, ESelectInfo::Type)) 行 65 C++
[内联框架] UE4Editor-PropertyEditor.dll!UE4Tuple_Private::TTupleBase<TIntegerSequence<unsigned int>>::ApplyAfter(void(SPropertyComboBox::*)(TSharedPtr<FString,0>, ESelectInfo::Type) &) 行 299 C++
UE4Editor-PropertyEditor.dll!TBaseSPMethodDelegateInstance<0,SPropertyComboBox,0,void __cdecl(TSharedPtr<FString,0>,enum ESelectInfo::Type),FDefaultDelegateUserPolicy>::ExecuteIfSafe(TSharedPtr<FString,0> <Params_0>, ESelectInfo::Type <Params_1>) 行 307 C++
UE4Editor-EditorWidgets.dll!TDelegate<void __cdecl(TSharedPtr<FString,0>,enum ESelectInfo::Type),FDefaultDelegateUserPolicy>::ExecuteIfBound<void,0>(TSharedPtr<FString,0> <Params_0>, ESelectInfo::Type <Params_1>) 行 599 C++
UE4Editor-EditorWidgets.dll!SSearchableComboBox::OnSelectionChanged_Internal(TSharedPtr<FString,0> ProposedSelection, ESelectInfo::Type SelectInfo) 行 211 C++
[内联框架] UE4Editor-EditorWidgets.dll!Invoke(void(SSearchableComboBox::*)(TSharedPtr<FString,0>, ESelectInfo::Type)) 行 65 C++
[内联框架] UE4Editor-EditorWidgets.dll!UE4Tuple_Private::TTupleBase<TIntegerSequence<unsigned int>>::ApplyAfter(void(SSearchableComboBox::*)(TSharedPtr<FString,0>, ESelectInfo::Type) &) 行 299 C++
UE4Editor-EditorWidgets.dll!TBaseSPMethodDelegateInstance<0,SSearchableComboBox,0,void __cdecl(TSharedPtr<FString,0>,enum ESelectInfo::Type),FDefaultDelegateUserPolicy>::ExecuteIfSafe(TSharedPtr<FString,0> <Params_0>, ESelectInfo::Type <Params_1>) 行 307 C++
UE4Editor-EditorWidgets.dll!TDelegate<void __cdecl(TSharedPtr<FString,0>,enum ESelectInfo::Type),FDefaultDelegateUserPolicy>::ExecuteIfBound<void,0>(TSharedPtr<FString,0> <Params_0>, ESelectInfo::Type <Params_1>) 行 599 C++
UE4Editor-EditorWidgets.dll!SListView<TSharedPtr<FString,0>>::Private_SignalSelectionChanged(ESelectInfo::Type SelectInfo) 行 947 C++
UE4Editor-EditorWidgets.dll!STableRow<TSharedPtr<FString,0>>::OnMouseButtonUp(const FGeometry & MyGeometry, const FPointerEvent & MouseEvent) 行 617 C++
[内联框架] UE4Editor-Slate.dll!FSlateApplication::RoutePointerUpEvent::__l8::<lambda_345a5758a2260d3d061d4759ff6c6cee>::operator()(const FArrangedWidget &) 行 4829 C++
UE4Editor-Slate.dll!FEventRouter::Route<FReply,FEventRouter::FToLeafmostPolicy,FPointerEvent,<lambda_345a5758a2260d3d061d4759ff6c6cee>>(FSlateApplication * ThisApplication, FEventRouter::FToLeafmostPolicy RoutingPolicy, FPointerEvent EventCopy, const FSlateApplication::RoutePointerUpEvent::__l8::<lambda_345a5758a2260d3d061d4759ff6c6cee> & Lambda, ESlateDebuggingInputEvent DebuggingInputEvent) 行 378 C++
UE4Editor-Slate.dll!FSlateApplication::RoutePointerUpEvent(const FWidgetPath & WidgetsUnderPointer, const FPointerEvent & PointerEvent) 行 4815 C++
UE4Editor-Slate.dll!FSlateApplication::ProcessMouseButtonUpEvent(const FPointerEvent & MouseEvent) 行 5356 C++
UE4Editor-Slate.dll!FSlateApplication::OnMouseUp(const EMouseButtons::Type Button, const FVector2D CursorPos) 行 5321 C++
UE4Editor-ApplicationCore.dll!FWindowsApplication::ProcessDeferredMessage(const FDeferredWindowsMessage & DeferredMessage) 行 2174 C++
UE4Editor-ApplicationCore.dll!FWindowsApplication::DeferMessage(TSharedPtr<FWindowsWindow,0> & NativeWindow, HWND__ * InHWnd, unsigned int InMessage, unsigned __int64 InWParam, __int64 InLParam, int MouseX, int MouseY, unsigned int RawInputFlags) 行 2638 C++
UE4Editor-ApplicationCore.dll!FWindowsApplication::ProcessMessage(HWND__ * hwnd, unsigned int msg, unsigned __int64 wParam, __int64 lParam) 行 1042 C++
UE4Editor-ApplicationCore.dll!FWindowsApplication::AppWndProc(HWND__ * hwnd, unsigned int msg, unsigned __int64 wParam, __int64 lParam) 行 874 C++
五、总结
简单来说,就是actor对应的Details面板中的属性主要是该Actor和它的组件(Component)中的属性列表。UE提供了一种通用的机制,只要在声明中添加了UPROPERTY属性,编辑器会自动展示这些属性,通过界面修改之后会自动修改内存对象对应属性成员。