ue5 创建多列StreeView的方法与理解

ops/2025/3/3 21:06:09/

创建StreeView的多列样式怎么就像是创建单行单列差不多?貌似就是在单行单列中加入了多列widget?

目录结构:

必备条件

StreeView的多列创建需要的必备条件:

数据基类

CustomItemBase 

#pragma once
/*
----------------------------------
| Name       | Value              |
----------------------------------
| 香蕉       | 真正的香蕉           |
----------------------------------
*/// 构建一个基类,相当于创建一个空的价签,其中包括(名字:价格:),具体怎么填由子类决定
class FCustomItemBase : public TSharedFromThis<FCustomItemBase>
{
public:virtual ~FCustomItemBase() {}// 比如要卖香蕉:名字:香蕉 ,Value :价格virtual TSharedRef<SWidget> MakeNameWidget() = 0;virtual TSharedRef<SWidget> MakeValueWidget() = 0;//当展示时需要先获取到这个价签后才能知道这是为哪个商品准备的价签(即:名字,价格)void GetChildrens(TArray<TSharedRef<FCustomItemBase>>& OutChildren) const{ OutChildren = Childrens;};private://用于保存传入的参数并通过OutChildren传出去TArray<TSharedRef<FCustomItemBase>> Childrens;
};/*
----------------------------------
| Name       | Value              |
----------------------------------
FCustomItemBase中有两个属性(name、Value),所以制作价签时就需要预留两个空位,使用SMultiColumnTableRow多列样式
创建继承至class SMultiColumnTableRow的类,查看基类样式为SMultiColumnTableRow : public STableRow<ItemType>
解释为: S类名 :public 基类<价签的引用>,有几个属性就安排几个位置(即:有两个属性,就安排两列),这是S类,所以需要S类的构造方法
如果是单列:STableRow,每行就只能放一个属性,明白了吗?
----------
| Name  |
----------
*/class SMultiDetailTableRow : public SMultiColumnTableRow<TSharedRef<FCustomItemBase>>
{SLATE_BEGIN_ARGS(SMultiDetailTableRow){}SLATE_END_ARGS()// 父类SMultiColumnTableRow中的方法,动态生成不同列的显示内容,必须实现的方法virtual TSharedRef<SWidget> GenerateWidgetForColumn( const FName& InColumnName ) override;// 父类方法中默认两个参数,第三个参数是因为创建时必须有FCustomItemBase才能正确显示void Construct(const FArguments& InArgs, const TSharedRef<STableViewBase>& OwnerTableView,TSharedRef<FCustomItemBase> InCustomItemBase);
private:// 这个弱指针是为了初始化时将传进来的FCustomItemBase赋值给CustomItemBase用于保存TWeakPtr<FCustomItemBase> CustomItemBase;
};
#include "CustomItemBase.h"//一行多列
TSharedRef<SWidget> SMultiDetailTableRow::GenerateWidgetForColumn(const FName& InColumnName)
{// 判断InColumnName,如果传入的是名字,就在价签的name中添加名字if (InColumnName.IsEqual(TEXT("Name"))){return CustomItemBase.Pin()->MakeNameWidget();}// 判断InColumnName,如果传入的是Value,就在价签的Value中添加价格if ((InColumnName.IsEqual(TEXT("Value")))){return CustomItemBase.Pin()->MakeValueWidget();}// 空widget用于占位return SNullWidget::NullWidget;
}//还是创建了一行两列,streeview中的多个行还是需要在生成树的类中创建
void SMultiDetailTableRow::Construct(const FArguments& InArgs, const TSharedRef<STableViewBase>& OwnerTableView,TSharedRef<FCustomItemBase> InCustomItemBase)
{//赋值保存CustomItemBase = InCustomItemBase;//STableRow::FArguments()是这个是原生的风格样式,生成时的样式布局(可替换)STableRow::FArguments ParentArgs;ParentArgs.Padding(FMargin(0,8,0,0));//调用基类的构造函数,查看基类中的Construct方法SMultiColumnTableRow::Construct(ParentArgs, OwnerTableView);}

 数据子类

CustomItemBool

#pragma once
#include "CustomItemBase.h"//价签的子类,父类中的价签已经印刷好了
class FCustomItemBool : public FCustomItemBase
{
public://创建后默认就是 falseFCustomItemBool():Value(false){}// 实现父类 CustomItemBase中的方法,做具体的事(即:具体的名字,具体的价格)virtual TSharedRef<SWidget> MakeNameWidget() override;virtual TSharedRef<SWidget> MakeValueWidget() override;private:void OnCheckStateChanged(ECheckBoxState CheckState);ECheckBoxState GetCheckBoxState() const;bool Value;
};
#include "CustomItemBool.h"TSharedRef<SWidget> FCustomItemBool::MakeNameWidget()
{//具体的名字Test Bool,显示中文必须用Text包裹:(TEXT("选中测试Bool")return SNew(STextBlock).Text(FText::FromString(TEXT("选中测试Bool")));
}TSharedRef<SWidget> FCustomItemBool::MakeValueWidget()
{//这里创建的是选择框,可以是选择框、下拉框...Bool类的控件return SNew(SCheckBox)//绑定点击状态,是否点击了,这是一个事件SLATE_EVENT( FOnCheckStateChanged, OnCheckStateChanged )//相当于点击了就触发点击事件,将这个事件与回调函数OnCheckStateChanged绑定,点击就触发.OnCheckStateChanged(this, &FCustomItemBool::OnCheckStateChanged)//点击后的状态,是选中了还是取消了,查看SLATE_ATTRIBUTE( ECheckBoxState, IsChecked )后不是知道是啥//继续查看enum class ECheckBoxState : uint8,里面有三种状态,那这个IsChecked()的参数是不是就是要这个枚举?//因为这里是绑定,需要回调函数,所以创建一个ECheckBoxState类型的函数试试,结果懵对了.IsChecked(this, &FCustomItemBool::GetCheckBoxState);
}void FCustomItemBool::OnCheckStateChanged(ECheckBoxState CheckState)
{//既然是回调函数,那么当被触发后要做什么?这个类是bool类型,非真即假//使用三目运算符 :给Value 赋值为 CheckState//CheckState的状态如果与ECheckBoxState::Checked 的状态相同,就是真,否则是假Value = CheckState == ECheckBoxState::Checked ? true : false; 
}ECheckBoxState FCustomItemBool::GetCheckBoxState() const
{//上面已经给Value赋值了,这里就问Value是什么?如果是真就是 ECheckBoxState::Checked了,否则。。。return Value? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
}

streetview组装类

CustomDetailPlane

#pragma once
#include "CustomItemBase.h"//这里是使用typedef创建别名的方式,用FCustomItemBase中的数据,创建了一个树,
typedef STreeView<TSharedRef<FCustomItemBase>> CustomDetailTreeView;class SCustomDetailPlane : public SCompoundWidget
{SLATE_BEGIN_ARGS(SCustomDetailPlane){}SLATE_END_ARGS()SCustomDetailPlane();virtual ~SCustomDetailPlane();void Construct(const FArguments& InArgs);//树形结构中的行,这里就是一行一列,这里可以再装入1行2列或是其他。。。TSharedRef<ITableRow> CustomOnGenerateRow(TSharedRef<FCustomItemBase> Item,const TSharedRef< STableViewBase >& TableView);//SLATE_EVENT( FOnGetChildren, OnGetChildren ),//事件类型,进一步查看API DECLARE_DELEGATE_TwoParams (FOnGetChildren,ArgumentType, TArray<ArgumentType>& );//TwoParams表示需要两个参数,没有返回值,因为是GetChildren,ArgumentType应该是Children父类,然后从父类获取包含的子类void OnGetChildren(TSharedRef<FCustomItemBase> ParentItem, TArray<TSharedRef<FCustomItemBase>>& OutChildrens);//当CustomItemBool类创建好后,这时已经在类中确定了要做的事,这里创建一个函数用于给TreeItemSources赋值测试void SetItemData();private:TSharedPtr<SWidgetSwitcher> WidgetSwitcher;//这里用的是上面创建的别名,生成指向STreeView<TSharedRef<FCustomItemBase>>的指针//因为STreeView<TSharedRef<FCustomItemBase>>太长,所以使用别名,也方便修改TSharedPtr<CustomDetailTreeView> OtherNameDetailTreeView;//树结构需要的数据源,(即已经准备好的价签,展台已经准备好了,需要几层就放入几个价签)TArray<TSharedRef<FCustomItemBase>> TreeItemSources;
};
#include "CustomDetailPlane.h"#include "CustomItemBool.h"
#include "Widgets/Layout/SWidgetSwitcher.h"SCustomDetailPlane::SCustomDetailPlane()
{
}SCustomDetailPlane::~SCustomDetailPlane()
{
}void SCustomDetailPlane::Construct(const FArguments& InArgs)
{ChildSlot[SAssignNew(WidgetSwitcher, SWidgetSwitcher)+ SWidgetSwitcher::Slot().HAlign(HAlign_Center).VAlign(VAlign_Center)[SNew(STextBlock).Text(FText::FromString("Custom Detail Plane"))]+ SWidgetSwitcher::Slot().HAlign(HAlign_Fill).VAlign(VAlign_Fill)[//生成树控件,只有树干SAssignNew(OtherNameDetailTreeView, CustomDetailTreeView)//设置数据源(即:准备好树枝).TreeItemsSource(&TreeItemSources)//绑定代理(将生成事件与实际生成方法绑定到一起).OnGenerateRow(this, &SCustomDetailPlane::CustomOnGenerateRow)//绑定代理(将获取事件与实际获取方法绑定到一起).OnGetChildren(this, &SCustomDetailPlane::OnGetChildren)//生成列.HeaderRow(SNew(SHeaderRow)+ SHeaderRow::Column("Name").HeaderContentPadding(FMargin(0)).FillWidth(0.4f)[SNew(SBorder).Padding(FMargin(20, 5, 5, 5))[SNew(STextBlock).Text(FText::FromString("Name"))]]+ SHeaderRow::Column("Value").HeaderContentPadding(FMargin(0)).FillWidth(0.6f)[SNew(SBorder).Padding(FMargin(20, 5, 5, 5))[SNew(STextBlock).Text(FText::FromString("Value"))]])]];SetItemData();
}TSharedRef<ITableRow> SCustomDetailPlane::CustomOnGenerateRow(TSharedRef<FCustomItemBase> Item,const TSharedRef<STableViewBase>& TableView)
{return SNew(SMultiDetailTableRow, TableView, Item);
}void SCustomDetailPlane::OnGetChildren(TSharedRef<FCustomItemBase> ParentItem,TArray<TSharedRef<FCustomItemBase>>& OutChildrens)
{ParentItem->GetChildrens(OutChildrens);
}void SCustomDetailPlane::SetItemData()
{//相当于实例化了一个FCustomItemBool类型的小控件BoolItem,等待显示TSharedRef<FCustomItemBool> BoolItem = MakeShareable(new FCustomItemBool());//在FCustomItemBool中已经将水果放到了果篮中并将果篮摆在了层板上,这里将层板放到树上TreeItemSources.Add(BoolItem);//这里如果你又创建了新的控件,就还用上面的MakeShareable(new FCustomItemBool());方法//然后用TreeItemSources.Add(BoolItem);添加//刷新OtherNameDetailTreeView->RequestTreeRefresh();//显示WidgetSwitcher的那一页WidgetSwitcher->SetActiveWidgetIndex(1);
}


http://www.ppmy.cn/ops/162521.html

相关文章

边缘计算收益低的三大指标

边缘计算收益低的三大指标主要包括以下方面&#xff1a; 1. 资源贡献不足&#xff1a; 边缘计算的收益通常基于所提供的带宽、存储和计算资源来计算。如果设备的网络带宽有限、在线时间短或提供的存储容量较小&#xff0c;可能无法满足平台设定的最低贡献标准&#xff0c;从而导…

在Linux上安装go环境

1、创建安装目录 [rootlocalhost ~]# mkdir go [rootlocalhost ~]# cd go/ 2、下载go文件解压 [rootlocalhost go]# wget https://golang.google.cn/dl/go1.24.0.linux-amd64.tar.gz [rootlocalhost go]# tar xf go1.24.0.linux-amd64.tar.gz 3、配置go环境变量 # 这里的路…

分布式数据存储:提升系统弹性与性能的技术之路

分布式数据存储:提升系统弹性与性能的技术之路 在当今数据爆炸式增长的时代,传统的单机存储系统已无法满足大规模、高并发、低延迟的需求。尤其是在大数据、云计算和物联网的推动下,数据存储面临着前所未有的挑战。分布式数据存储应运而生,通过将数据分布在多个物理节点上…

在 SQLite 中使用 SpatiaLite 实现地理空间数据自动化读写

地理空间数据&#xff08;如坐标点、区域边界&#xff09;的存储与查询是物联网、位置服务等领域的常见需求。本文提供一套简洁的解决方案&#xff0c;利用 SQLite 和 SpatiaLite 扩展&#xff0c;通过触发器和视图实现以下目标&#xff1a; 写入简化&#xff1a;直接插入人类…

Spring-AI搭建企业专属知识库 一

环境介绍&#xff1a;Spring3.3.2 JDK 21 POM文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation&…

[思考记录]AI时代下,悄然的改变

尝试用 xAI-Grok 去了解DS开源周的信息&#xff0c;有那么点被Grok的输出惊艳到。“请你以技术编辑的角色&#xff0c;重点参考官方文档&#xff0c;介绍DeepSeek开源周的内容&#xff0c;写一篇技术分享文章。”&#xff0c;得到的文字看起来很是舒服&#xff0c;内容靠谱、结…

说一下接口测试流程有哪些?

接口测试流程通常分为六个阶段&#xff1a; 需求分析时&#xff0c;我会仔细阅读接口文档&#xff0c;明确参数规则和业务场景&#xff1b; 设计用例会覆盖正常、异常和边界场景&#xff0c;比如用等价类划分设计订单金额的测试数据&#xff1b; 环境准备阶段&#xff0c;可能…

从黑暗到光明:FPC让盲人辅助眼镜成为视障者的生活明灯!【新立电子】

在科技日新月异的今天&#xff0c;智能技术正以前所未有的方式改变着我们的生活。对于视障人士而言&#xff0c;科技的进步更是为他们打开了一扇通往更加独立自主生活的大门。其中&#xff0c;盲人辅助智能眼镜可以成为视障人士日常生活中的得力助手。FPC在AR眼镜中的应用&…