UE 树形图 C++版
1.创建以下三个C类(1)UTreeViewItemBase(基类UObject)UCLASS() class UTreeViewItemBase : public UObject { GENERATED_BODY() public: UTreeViewItemBase(); virtual ~UTreeViewItemBase() override; public: FString Id; //层级 int32 Level; //标签 FText Label; //与自身对应的Actor AActor* SelfActor; //SelfActor 的初始材质 TArraylt;UMaterialInterface*gt;OriginalMaterials; //子级Item数组 TArraylt;UObject*gt; ChildrenData; }该类型为树形图三要素中的Item①Level:决定Item对应Entry的在树形图中的层级结构,如下图1-1②Label:Entry显示的文本③SelfActor: Actor-Item-Entry. Item是Actor和Entry之间的桥梁,如下图1-2④ChildrenData:存储本级Item的子级Item对象(2)UEntryWidgetBase(基类UUserWidget,实现接口IUserObjectListEntry)UCLASS() class UEntryWidgetBase : public UUserWidget,public IUserObjectListEntry { GENERATED_BODY() public: //override begin virtual void NativeConstruct() override; virtual void NativePreConstruct() override; virtual void NativeOnInitialized() override; //override end public: //子级entry缩进像素长度 UPROPERTY(EditAnywhere,BlueprintReadOnly,Categoryquot;EntryWidgetBasequot;) float SubItemIndentWidth20.f; UCheckBox* CheckBox; UTextBlock* TextBlock; UHorizontalBox* HorBox; UTreeView* TreeView; protected: //Entry对应的Item UTreeViewItemBase* ListItemObject; }该类型为树形图三要素中的Entry①CheckBox,TextBlock,HorBox控件,如下图1-3②ListItemObject:Entry对应的Item(3)UTreeViewPanelBase(基类UUserWidget)UCLASS() class UTreeViewPanelBase : public UUserWidget { GENERATED_BODY() public: UTreeViewPanelBase(const FObjectInitializeramp; ObjectInitializer); //override begin virtual void NativeConstruct() override; virtual void NativePreConstruct() override; virtual bool Initialize() override; //override end UTreeView* TreeView; }该类型为树形图三要素中的TreeView2.成员函数说明(1)UTreeViewItemBase类中定义以下成员函数public: //初始化子级 void InitChildren(); /** * brief 设置子级隐藏 * param bHidden true:隐藏;false:显示 */ void SetChildrenHiddenInGame(bool bHidden); /** * brief 缓存对应的模型的初始材质 */ void CacheOriginalMaterials(); /** * brief 被选中状态,材质更换 */ void OnSelected(); /** * brief 取消选中状态,材质恢复 */ void UnSelected(); /** * brief 根据选中的Actor找到其对应的Item * param SelectedActor 选中的Actor * param OutItem 对应的item */ void FindSubItemByGivenActor(AActor* SelectedActor,UObject*amp;OutItem);解析:①InitChildrenvoid UTreeViewItemBase::InitChildren() { UnSelected(); //缓存初始材质 CacheOriginalMaterials(); //获得所有子级actor TArraylt;AActor*gt;AttachedActors; SelfActor-gt;GetAttachedActors(AttachedActors); ChildrenData.Reset(); //为所有子级actor创建对应的子级item for(int i0;ilt;AttachedActors.Num();i) { if (!AttachedActors[i]) continue; UTreeViewItemBase* ItemNewObjectlt;UTreeViewItemBasegt;(this); Item-gt;IdFString::Printf(TEXT(quot;%s_%dquot;),*Id,i); Item-gt;LevelLevel1; Item-gt;LabelFText::FromString(UKismetSystemLibrary::GetDisplayName(AttachedActors[i])); Item-gt;SelfActorAttachedActors[i]; Item-gt;InitChildren(); ChildrenData.Add(Item); } }该成员函数用于查找SelfActor存在多少个子级Actor,然后为每个子级创建子级Item,并将子级Item与子级Actor建立对应关系.ps:初始化子级时要注意,子级可能也有子级,所以需要通过递归逐级往下初始化②SetChildrenHiddenInGamevoid UTreeViewItemBase::SetChildrenHiddenInGame(bool bHidden) { //设置对应actor的显隐性 SelfActor-gt;SetActorHiddenInGame(bHidden); //递归设置子级显隐性 for (UObject*amp; ChildObject:ChildrenData) { UTreeViewItemBase* ChildItemCastlt;UTreeViewItemBasegt;(ChildObject); if (ChildItem) { ChildItem-gt;SetChildrenHiddenInGame(bHidden); } } }该成员函数用于控制子级Actor(包含自身)的显隐性,如2-1③CacheOriginalMaterialsvoid UTreeViewItemBase::CacheOriginalMaterials() { //获得static mesh 组件 UStaticMeshComponent* StaticMeshCompCastlt;UStaticMeshComponentgt;(SelfActor-gt;GetComponentByClass(UStaticMeshComponent::StaticClass())); if (StaticMeshComp amp;amp; StaticMeshComp-gt;GetStaticMesh()) { TArraylt;UMaterialInterface*gt;Materials; MaterialsStaticMeshComp-gt;GetMaterials(); OriginalMaterialsMaterials; } }该函数用于缓存SelfActor的初始材质④OnSelectedvoid UTreeViewItemBase::OnSelected() { //获得静态网格组件 UStaticMeshComponent* SMCCastlt;UStaticMeshComponentgt;(SelfActor-gt;GetComponentByClass(UStaticMeshComponent::StaticClass())); if(!SMC) return; //下面注释部分是从配置文件中读取高亮材质,本篇教程不对配置文件进行赘述,可自行加载一个材质用于实现选中高亮效果,如LoadObject /****************************** //获得树形图工具配置文件 UTreeViewToolSettings* TreeViewToolSettingsUTreeViewToolSettings::GetTreeViewToolSettings(); //获得配置文件里配置的高亮材质 TSoftObjectPtrlt;UMaterialInterfacegt; MaterialTreeViewToolSettings-gt;HightLightMaterial.LoadSynchronous(); if (!Material.IsValid()) return; ***********************************************/ //将所有材质设置为高亮 int MaterialNumSMC-gt;GetNumMaterials(); for (int i0;ilt;MaterialNum;i) { UMaterialInstanceDynamic* DMISMC-gt;CreateDynamicMaterialInstance(i,Material.Get()); DMI-gt;SetVectorParameterValue(FName(quot;HightLightColorquot;),TreeViewToolSettings-gt;Color); } }该函数实现了点击Entry,使其对应的Actor高亮(被选中效果) ,效果如参考图2-1⑤UnSelectedvoid UTreeViewItemBase::UnSelected() { //获得static mesh组件 UStaticMeshComponent* SMCCastlt;UStaticMeshComponentgt;(SelfActor-gt;GetComponentByClass(UStaticMeshComponent::StaticClass())); if(!SMC) return; //重置材质为原始材质 for (int i0;ilt;OriginalMaterials.Num();i) { SMC-gt;SetMaterial(i,OriginalMaterials[i]); } for(UObject* Child:ChildrenData) { if(UTreeViewItemBase* ChildItemCastlt;UTreeViewItemBasegt;(Child)) { //递归取消选中状态 ChildItem-gt;UnSelected(); } } }该函数实现了取消选中效果,使其对应的Actor由选中高亮效果恢复到初始材质⑥FindSubItemByGivenActorvoid UTreeViewItemBase::FindSubItemByGivenActor(AActor* SelectedActor, UObject*amp; OutItem) { if(SelfActorSelectedActor) { OutItemthis; return; } for (UObject*amp;ChildObj:ChildrenData) { UTreeViewItemBase*ChildItemCastlt;UTreeViewItemBasegt;(ChildObj); ChildItem-gt;FindSubItemByGivenActor(SelectedActor,OutItem); } }该函数用于查找与给定Actor对应的Item,用于点击Actor反向定位树形图中的Entry,如下图(2)UEntryWidgetBaseNativeOnInitialized(初始化函数)实现void UEntryWidgetBase::NativeOnInitialized() { Super::NativeOnInitialized(); //获得umg 控件 TextBlockCastlt;UTextBlockgt;(GetWidgetFromName(FName(quot;Textblockquot;))); CheckBoxCastlt;UCheckBoxgt;(GetWidgetFromName(FName(quot;CheckBoxquot;))); HorBoxCastlt;UHorizontalBoxgt;(GetWidgetFromName(FName(quot;HorBoxquot;))); //绑定checkbox勾选状态改变回调 if(CheckBox) { CheckBox-gt;OnCheckStateChanged.AddDynamic(this,amp;UEntryWidgetBase::OnCheckBoxStateChanged); } //默认勾选状态 CheckBox-gt;SetCheckedState(ECheckBoxState::Checked); }类中定义以下成员函数public: /** * brief 推测Entry的勾选状态 * param Item entry对应的Item * return 勾选状态 */ ECheckBoxState PredictEntryState(UTreeViewItemBase* Item); /** * brief 递归刷新entry的上一级entry状态 */ void RefreshParentEntries(); /** * brief 递归刷新子级entry状态 * param State 子级状态受父级entry checkbox控件选中状态影响 */ void RefreshChildrenEntries(ECheckBoxState State); /** * brief 刷新各级Entry状态 * param State checkbox 控件选中状态 */ void RefreshHierarchyState(ECheckBoxState State); /** * brief checkbox控件选中状态更改回调函数 * param bIsChecked 是否勾选 */ UFUNCTION() void OnCheckBoxStateChanged(bool bIsChecked); /** * brief 根据entry选中状态切换字体 * param bIsSelected 选中:粗体;未选中:正常字体 */ void SwitchFontBySelectState(bool bIsSelected); /** * brief 根据entry选中状态更新对应模型的高亮效果 * param bIsSelected 选中高亮,未选中恢复正常 */ void SwitchMaterialBySelectState(bool bIsSelected); protected: //IUserObjectListEntry begin void NativeOnListItemObjectSet(UObject* ListItemObject) override; void NativeOnItemSelectionChanged(bool bIsSelected) override; void NativeOnEntryReleased() override; //IUserObjectListEntry end解析:①PredictEntryState(推测Entry状态)ECheckBoxState UEntryWidgetBase::PredictEntryState(UTreeViewItemBase* Item) { ECheckBoxState StateECheckBoxState::Checked; //注1: int Count0; if (!Item) return State; //统计子级Entry勾选checkbox的数量 if (Item-gt;ChildrenData.Num()gt;0) { for (UObject*amp; ChildData:Item-gt;ChildrenData) { UEntryWidgetBase* ChildEntryCastlt;UEntryWidgetBasegt;(TreeView-gt;GetEntryWidgetFromItem(ChildData));: if (ChildEntry) { ECheckBoxState ChildStateChildEntry-gt;CheckBox-gt;GetCheckedState(); switch (ChildState) { case ECheckBoxState::Checked: Count; break; case ECheckBoxState::Undetermined: Count10000; break; default: break; } } //entry无效(不显示时)以对应item的actor显隐性为准 else { UTreeViewItemBase* ChildItemCastlt;UTreeViewItemBasegt;(ChildData); if (ChildItem) CountChildItem-gt;SelfActor-gt;IsHidden()?0:1; } } //注2 StateItem-gt;ChildrenData.Num()Count?ECheckBoxState::Checked:ECheckBoxState::Undetermined; } //没有子级时,以对应item的actor的显隐性为准,显示checked;隐藏unchecked else { StateItem-gt;SelfActor-gt;IsHidden()?ECheckBoxState::Unchecked:ECheckBoxState::Checked; } return State; }注1:父级的勾选状态(checkbox)受子级影响.通过对比子级已勾选数量对比子级数量来决定父级的勾选状态.注2:子级Entry全部Checked(子级数量Count):父级Checked子级Entry部分Checked 或者 全部UnChecked(子级数量!Count):父级Undetermined参考如下图2-22-2②RefreshParentEntries(刷新父级Entry状态)void UEntryWidgetBase::RefreshParentEntries() { if(!TreeView) return; //获得父级item和entry UTreeViewItemBase* ParentItemCastlt;UTreeViewItemBasegt;(ListItemObject-gt;GetOuter()); UEntryWidgetBase* ParentEntryCastlt;UEntryWidgetBasegt;(TreeView-gt;GetEntryWidgetFromItem(ParentItem)); if (ParentEntry) { //推测父级checkbox状态 ECheckBoxState ParentStatePredictEntryState(ParentItem); ParentEntry-gt;CheckBox-gt;SetCheckedState(ParentState); //递归刷新更上一级父级 ParentEntry-gt;RefreshParentEntries(); } }向上递归刷新父级Entry的状态,效果参考2-2③RefreshChildrenEntries(刷新子级Entry状态)void UEntryWidgetBase::RefreshChildrenEntries(ECheckBoxState State) { if(!TreeView) return; //刷新子级checkbox和启用状态 for(UObject*amp; ChildData:ListItemObject-gt;ChildrenData) { UEntryWidgetBase* EntryTreeView-gt;GetEntryWidgetFromItemlt;UEntryWidgetBasegt;(ChildData); //entry有效时设置勾选状态 if (Entry) { Entry-gt;CheckBox-gt;SetCheckedState(State); Entry-gt;RefreshChildrenEntries(State); } } }遍历递归更新本级Entry的子级Entry(以及子级的子级)的状态.效果参考2-2④RefreshHierarchyState(刷新层级结构状态,即子父级一块刷新)void UEntryWidgetBase::RefreshHierarchyState(ECheckBoxState State) { if(StateECheckBoxState::Undetermined) return; //根据勾选状态更新对应的Actor的显隐性 ListItemObject-gt;SetChildrenHiddenInGame(CheckBox-gt;GetCheckedState()ECheckBoxState::Unchecked); RefreshChildrenEntries(State); RefreshParentEntries(); }效果参考2-2④OnCheckBoxStateChanged(Checkbox勾选状态改变回调)void UEntryWidgetBase::OnCheckBoxStateChanged(bool bIsChecked) { RefreshHierarchyState(bIsChecked?ECheckBoxState::Checked:ECheckBoxState::Unchecked); }该回调函数在本篇开头NativeOnInitialized中绑定.2-3⑤SwitchFontBySelectState(选中切换字体)void UEntryWidgetBase::SwitchFontBySelectState(bool bIsSelected) { //此处字体选择逻辑仅为示例,实际使用建议将字体公开到蓝图,可在蓝图中进行手动选择 UFont* FontObjectnullptr; if(bIsSelected) { FontObjectLoadObjectlt;UFontgt;(nullptr,TEXT(quot;/Engine/EngineFonts/BoldFontquot;)); } else { FontObjectLoadObjectlt;UFontgt;(nullptr,TEXT(quot;/Engine/EngineFonts/Robotoquot;)); } //设置字体 if(FontObject) { FSlateFontInfo FontInfoTextBlock-gt;GetFont(); FontInfo.FontObjectFontObject; TextBlock-gt;SetFont(FontInfo); } }效果参考2-3⑥SwitchMaterialBySelectState(选中高亮)void UEntryWidgetBase::SwitchMaterialBySelectState(bool bIsSelected) { //根据选中状态更换材质 if (bIsSelected) { ListItemObject-gt;OnSelected(); } else { ListItemObject-gt;UnSelected(); } }效果参考2-3⑦NativeOnListItemObjectSetvoid UEntryWidgetBase::NativeOnListItemObjectSet(UObject* ItemObject) { //获取TreeView TreeViewCastlt;UTreeViewgt;(GetOwningListView()); //获得对应的Item ListItemObjectCastlt;UTreeViewItemBasegt;(ItemObject); //设置标签字体,文本内容和字体大小,字体大小与level挂钩,级别越高字体越大 TextBlock-gt;SetText(ListItemObject-gt;Label); FSlateFontInfo FontInfoTextBlock-gt;GetFont(); FontInfo.SizeUKismetMathLibrary::MapRangeClamped(ListItemObject-gt;Level,1,6,15,8); TextBlock-gt;SetFont(FontInfo); //根据Entry的level调整文本缩进长度 UBorderSlot* BorderSlotCastlt;UBorderSlotgt;(HorBox-gt;Slot); if (BorderSlot) { BorderSlot-gt;SetPadding(FMargin(ListItemObject-gt;Level*SubItemIndentWidth,0,0,0)); } CheckBox-gt;SetCheckedState(PredictEntryState(ListItemObject)); RefreshParentEntries(); }该接口函数触发时会返回Entry对应的Item,根据Item的成员变量Level(层级结构的级别,级树形图中的第n级)来决定Entry的字体大小以及文本缩进长度,如下图2-42-4⑧NativeOnItemSelectionChangedvoid UEntryWidgetBase::NativeOnItemSelectionChanged(bool bIsSelected) { //根据选中状态更换字体和材质 SwitchFontBySelectState(bIsSelected); if(bIsSelected) { ListItemObject-gt;OnSelected(); } else { ListItemObject-gt;UnSelected(); } }该接口函数在Entry的选中状态改变时触发,效果参考2-3⑨NativeOnEntryReleasedvoid UEntryWidgetBase::NativeOnEntryReleased() { SwitchFontBySelectState(false); SwitchMaterialBySelectState(false); }该接口在Entry被释放的时候触发,将字体和Actor材质还原.Entry在以下情况会被释放:1.子级Entry被折叠收起时会触发Release,此外,被展开时会触发NativeOnListItemObjectSet2.Entry不被绘制时,即在视口中不可见,如随着scrollbox滑动导致看不见,同理,当Entry重新被绘制时,触发NativeOnListItemObjectSet两种情况效果如下图2-52-5(3)UTreeViewPanelBaseNativeConstruct函数实现void UTreeViewPanelBase::NativeConstruct() { Super::NativeConstruct(); TreeViewCastlt;UTreeViewgt;(GetWidgetFromName(FName(quot;TreeViewquot;))); //绑定回调函数 TreeView-gt;SetOnGetItemChildrenlt;UTreeViewPanelBasegt;(this,amp;UTreeViewPanelBase::OnGetItemChildren); }类中定义以下成员函数/** * brief 查找actor的父级 * param Actor 要被查找父级的actor * param bFindTopLevelParent 是否查找最上级父级 */ void FindParentActor(AActor*amp; GivenActor,bool bFindTopLevelParenttrue); UFUNCTION(BlueprintCallable,Categoryquot;TreeViewPanelquot;) void StartSelect(); /** * brief 选中一个actor用于显示其层级结构 * param Level 层级级别 * param Actor 选中的Actor * param bUseTopLevelParent 是否使用选中actor的最上级父类作为层级结构起点 */ UFUNCTION(BlueprintCallable,Categoryquot;TreeViewPanelquot;) void OnSelectActor(const int32 Level,AActor* Actor,bool bUseTopLevelParenttrue); /** * brief 展开所有Item */ UFUNCTION(BlueprintCallable,Categoryquot;TreeViewPanelquot;) void ExpandAllItems(); /** * brief * param Item 展开单个Item */ void ExpandItem(UObject* Item); /** * brief 收起所有Item */ UFUNCTION(BlueprintCallable,Categoryquot;TreeViewPanelquot;) void CollapseAllItem(); /** * brief 刷新树形图 */ void RefreshTreeView(); /** * brief 获得item children回调函数 * param Item * param Children */ UFUNCTION() void OnGetItemChildren(UObject* Item,TArraylt;UObject*gt;amp; Children);解析:①FindParentActor3-1void UTreeViewPanelBase::FindParentActor(AActor*amp; GivenActor, bool bFindTopLevelParent) { if(!Acotr) return; //获得父级actor AActor* ParentActorAcotr-gt;GetAttachParentActor(); if (ParentActor) { AcotrParentActor; //递归继续查找更上层父级 if (bFindTopLevelParent) { FindParentActor(Acotr,bFindTopLevelParent); } } }GivenActor:选中的Actor(例如被鼠标点击到的)bFindTopLevelParent:true表示查找层级结构中的最上级,如传入参考图3-1中的Cone,返回Cubefalse表示查找结构中的上级,如传入Cone返回Sphere②StartSelect(选取场景中Actor)void UTreeViewPanelBase::StartSelect() { APlayerController* PlayerControllerGetWorld()-gt;GetFirstPlayerController(); if(PlayerController-gt;IsInputKeyDown(EKeys::RightMouseButton)) return; FVector Location,Direction; if(PlayerController-gt;DeprojectMousePositionToWorld(Location,Direction)) { FHitResult HitResult; bool bHitUKismetSystemLibrary::LineTraceSingle( this, Location, Direction*100000.fLocation, ETraceTypeQuery::TraceTypeQuery1, true,TArraylt;AActor*gt;(), EDrawDebugTrace::ForOneFrame, HitResult, true); if (bHit) { OnSelectActor(1,HitResult.GetActor(),true); } } }③OnSelectActor(选中Actor)void UTreeViewPanelBase::OnSelectActor(const int32 Level, AActor* Actor, bool bUseTopLevelParent) { //查找模型最上级的层级 AActor*ParentActorActor; FindParentActor(ParentActor,bUseTopLevelParent); if (!ParentActor) return; bool bNeedRebuildTreeViewtrue; if(TreeView-gt;GetListItems().IsValidIndex(0)) { UTreeViewItemBase* RootItemCastlt;UTreeViewItemBasegt;(TreeView-gt;GetListItems()[0]); //注1 if(RootItem-gt;SelfActorParentActor) { bNeedRebuildTreeViewfalse; UObject* OutItemnullptr; RootItem-gt;FindSubItemByGivenActor(Actor,OutItem); if (OutItem) { TArraylt;UUserWidget*gt; EntryWidgetsTreeView-gt;GetDisplayedEntryWidgets(); for (UUserWidget*amp; EntryWidget:EntryWidgets) { UEntryWidgetBase* EntryCastlt;UEntryWidgetBasegt;(EntryWidget); UObject* ItemObjEntry-gt;GetListItemlt;UObjectgt;(); //注2 TreeView-gt;SetItemSelection(ItemObj,false); } //注3 TreeView-gt;RequestNavigateToItem(OutItem); TreeView-gt;SetItemSelection(OutItem,true); } } } //重新构建树形图 if (bNeedRebuildTreeView) { UE_LOG(LogTemp,Warning,TEXT(quot;Select a new object :%squot;),*ParentActor-gt;GetName()); UTreeViewItemBase* ItemNewObjectlt;UTreeViewItemBasegt;(this); Item-gt;Idquot;0quot;; Item-gt;LevelLevel; Item-gt;LabelFText::FromString(UKismetSystemLibrary::GetDisplayName(ParentActor)); Item-gt;SelfActorParentActor; Item-gt;InitChildren(); TreeView-gt;ClearListItems(); TreeView-gt;AddItem(Item); } //展开所有item ExpandAllItems(); }注1:判断选中的Actor的父级Actor是否是上次选中的(即是否切换目标),如下图3-23-2注2:在未切换目标的情况下,将未被选中的子Entry设为未选择状态(未高亮)注3:将选中的Entry设为已选中(高亮)效果如下图3-33-3④ExpandItem(展开单个) ExpandAllItems(展开所有Item)引擎提供的ExpandAll并不能真正的展开所有的层级结构3-4调用引擎提供的ExpandAll仅能展开了一层结构,效果如3-53-5为此我们需要自行实现ExpandAll功能,代码如下void UTreeViewPanelBase::ExpandItem(UObject* Item) { TreeView-gt;SetItemExpansion(Item,true); UTreeViewItemBase* TreeViewItemCastlt;UTreeViewItemBasegt;(Item); for (UObject*amp; ChildItem:TreeViewItem-gt;ChildrenData) { if(ChildItem) { //递归展开当前Item的Children ExpandItem(ChildItem); } } } void UTreeViewPanelBase::ExpandAllItems() { //官方提供的expandall节点智能展开一级entry,再深层子级无法展开 TreeView-gt;ExpandAll(); //手动展开item TArraylt;UObject*gt; ItemsTreeView-gt;GetListItems(); if (Items.IsValidIndex(0)) { ExpandItem(Items[0]); } }⑤CollapseAllItem(折叠收起所有Item)void UTreeViewPanelBase::CollapseAllItem() { TreeView-gt;CollapseAll(); }⑥RefreshTreeView(刷新层级结构)void UTreeViewPanelBase::RefreshTreeView() { if(TreeView-gt;GetListItems().IsValidIndex(0)) { UTreeViewItemBase* RootItemCastlt;UTreeViewItemBasegt;(TreeView-gt;GetListItems()[0]); RootItem-gt;InitChildren(); TreeView-gt;ClearListItems(); TreeView-gt;AddItem(RootItem); ExpandAllItems(); } }注1:Treeview通过GetListItems获得的Item数组中,第0个元素表示根Item注2:刷新时清空原有的Item注3:默认刷新时展开所有层级,可根据自身需求选择,不想展开就是执行ExpandAllItems⑦OnGetItemChildrenvoid UTreeViewPanelBase::OnGetItemChildren(UObject* Item,TArraylt;UObject*gt;amp; Children) { UTreeViewItemBase* TreeViewItemCastlt;UTreeViewItemBasegt;(Item); if(!TreeViewItem) return; ChildrenTreeViewItem-gt;ChildrenData; }该函数在Treeview执行AddItem时自动触发.一.创建UMG1.WBP_EntryWidget1-12.WBP_TreeViewPanel1-2代码如下1-3解析:(1)使用右键鼠标进行选择目标(2)EventOnMouseEnter和EventIOnMouseLeave 事件为了防止鼠标穿透UI选中目标二.演示至此树形图功能讲解完毕!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2419978.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!