一、如何展示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屬性,編輯器會自動展示這些屬性,通過界面修改之后會自動修改內存對象對應屬性成員。