Unreal UMG 遍历所有控件


Unreal UMG 如果你对获取某个Widget的子节点数量不对,发现少了,有些子节点没获取到,可以注意一下这个下述方法。
GetChildWidgets,GetAllWidgets等获取的数量不对的情况。
下述是UMG遍历子节点的实现代码


void UWidgetTree::ForWidgetAndChildren(UWidget* Widget, TFunctionRef Predicate)
{
   // Search for any named slot with content that we need to dive into.
   if ( INamedSlotInterface* NamedSlotHost = Cast(Widget) )
   {
   	TArray SlotNames;
   	NamedSlotHost->GetSlotNames(SlotNames);

   	for ( FName SlotName : SlotNames )
   	{
   		if ( UWidget* SlotContent = NamedSlotHost->GetContentForSlot(SlotName) )
   		{
   			Predicate(SlotContent);

   			ForWidgetAndChildren(SlotContent, Predicate);
   		}
   	}
   }

   // Search standard children.
   if ( UPanelWidget* PanelParent = Cast(Widget) )
   {
   	for ( int32 ChildIndex = 0; ChildIndex < PanelParent->GetChildrenCount(); ChildIndex++ )
   	{
   		if ( UWidget* ChildWidget = PanelParent->GetChildAt(ChildIndex) )
   		{
   			Predicate(ChildWidget);

   			ForWidgetAndChildren(ChildWidget, Predicate);
   		}
   	}
   }
}

上述代码中我们知道大概的意思,获取凡是继承自UPanelWidget,或者实现了INamedSlotInterface的
Unreal中大量组件是没有继承自UPanelWidget的。所以就会遇到很多时候获取的子节点数量少了的情况。
例如:

	class UMG_API UListViewBase : public UWidget

	class UMG_API UDynamicEntryBoxBase : public UWidget 

所以上述组件默认是肯定遍历不到的,这也是为啥获取子节点没有达到自己预期的数量,那么Unreal给出的解决办法是实现INamedSlotInterface。
可以参考下述实现方案:

// ListView
void UListViewBase::GetSlotNames(TArray& SlotNames) const
{
	for (UWidget* Binding : GetDisplayedEntryWidgets())
	{
			SlotNames.Add(Binding->GetFName());
	}
}

UWidget* UListViewBase::GetContentForSlot(FName SlotName) const
{
	for (UWidget*  Binding : GetDisplayedEntryWidgets())
	{
		if (Binding->GetFName() == SlotName)
		{
			return Binding;
		}
	}

	return nullptr;
}

// DynamicEntryBox
	
void UDynamicEntryBoxBase::GetSlotNames(TArray& SlotNames) const
{
	for (const UWidget* Binding : GetAllEntries())
	{
		SlotNames.Add(Binding->GetFName());
	}
}

UWidget* UDynamicEntryBoxBase::GetContentForSlot(FName SlotName) const
{
	for (UWidget* Binding : GetAllEntries())
	{
		if (Binding->GetFName() == SlotName)
		{
			return Binding;
		} 
	}

	return nullptr;
}

GetChildWidgets,GetAllWidgets 底层实现依赖于ForWidgetAndChildren。
该文章就是UMG获取子节点数量不对的原因&解决办法。