1. UI的绑定
在C++中创建并设计UMG是非常不方便的事情,因此往往在蓝图的UMG中设计好UI,再在C++中绑定UI,在C++中完成数据的处理、事件的绑定、委托的调用各种事情,只需在UMG中完成页面的设计部分。
我们以下图例子为例
上图中橙色和红色的框是我们需要绑定的控件,橙色的是本身就存在的基础控件,红色的是我们自定义的一些控件。
对应上图的控件,我们使用UEC++完成绑定如下:
protected:
/** 自定义类型绑定,对应上图红色标记 */
UPROPERTY(meta=(BindWidget))
class UUI_BackpackListBase* OutBackpackList;
/** 自定义类型绑定 */
UPROPERTY(meta=(BindWidget))
class UUI_BackpackListBase* InBackpackList;
/** 基础控件绑定,对应上图橙色标记 */
UPROPERTY(meta=(BindWidget))
class UComboBoxString* ItemTypeComboBox;
注意:在C++中绑定的变量名要与UMG中的名称完全一致,然后UMG继承该类完成绑定,否则继承时会报错。
2. 控件Event的调用
我们现在需要在C++中调用上图的事件,比如一个Button
现在需要调用On Click怎么办呢?我们在C++中使用委托实现。
我们可以在C++源码,或者蓝图看这个委托是什么。
知道了该调用事件的参数之后就好办了,我们直接创建绑定委托的函数就好
/** 构造函数 */
void UUI_BackpackMain::NativeConstruct()
{
Super::NativeConstruct();
/** 绑定ComboBox的On Selection Changed事件 */
ItemTypeComboBox->OnSelectionChanged.AddDynamic(this, &UUI_BackpackMain::ComboBoxStringChanged);
;
/** 绑定的代理事件,注意参数要与上图一致 */
void UUI_BackpackMain::ComboBoxStringChanged(FString SelectedOption, ESelectInfo::Type SelectInfo)
{
// 执行需要调用的事件
}
3. 基本事件的使用
在UMG中,我们能使用很多重载的函数,包括Construct、Pre Construct等常用的函数。
在C++中我们输入NativeXXX(),可以找到这些我们熟悉的函数。
4. UI的拖拽
我们能在基本事件中,找到拖拽相关的函数
/** 当拖拽进入事件 */
virtual void NativeOnDragEnter(const FGeometry& InGeometry, const FDragDropEvent& InDragDropEvent, UDragDropOperation* InOperation) override;
/** 当拖拽离开事件 */
virtual void NativeOnDragLeave(const FDragDropEvent& InDragDropEvent, UDragDropOperation* InOperation) override;
/** 当拖拽结束时事件 */
virtual bool NativeOnDrop(const FGeometry& InGeometry, const FDragDropEvent& InDragDropEvent, UDragDropOperation* InOperation) override;
/** 继承自父类,当拖拽被发现时 */
virtual void NativeOnDragDetected(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent, UDragDropOperation*& OutOperation) override;
实现流程如下:
(1)在鼠标点击时,使用UWidgetBlueprintLibrary::DetectDragIfPressed
,将会调用NativeOnDragDetected
。
(2)在NativeOnDragDetected
中创建拖拽事件,将需要的Tag
和Payload
进行传参。
(3)在NativeOnDrop
中拿到InOperation
的Tag
和Payload
进行后续的处理。
基本实现如下:
/** 1. 鼠标点击 */
FReply UUI_InventoryCellBase::NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent)
{
Super::NativeOnMouseButtonDown(InGeometry, InMouseEvent);
// 如果鼠标左键按下,则返回DetectDrag,调用NativeOnDragDetected()函数
return UWidgetBlueprintLibrary::DetectDragIfPressed(InMouseEvent, this, EKeys::LeftMouseButton).NativeReply;
}
/** 2. 创建拖拽事件 */
void UUI_InventoryCellBase::NativeOnDragDetected(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent, UDragDropOperation*& OutOperation)
{
Super::NativeOnDragDetected(InGeometry, InMouseEvent, OutOperation);
/** 创建拖拽事件 */
UDragDropOperation* Temp = UWidgetBlueprintLibrary::CreateDragDropOperation(BaseDragDropOperation);
Temp->Tag = DragTag;
// 拖拽事件的通信参数,Object类型
Temp->Payload = this;
// 拖拽时,显示的样式
Temp->DefaultDragVisual = this;
// 拖拽事件的相对锚点
Temp->Pivot = EDragPivot::MouseDown;
Temp->Offset = FVector2d(0.f,0.f);
/** 将拖拽事件返回 */
OutOperation = Temp;
}
/** 3. 在NativeOnDrop中处理拖拽结束后的事情 */
bool UUI_BackpackListBase::NativeOnDrop(const FGeometry& InGeometry, const FDragDropEvent& InDragDropEvent,
UDragDropOperation* InOperation)
{
/** 使用InOperation进行后续操作 */
InOperation
return Super::NativeOnDrop(InGeometry, InDragDropEvent, InOperation);
}
5. 委托的绑定与调用
在UMG中常常使用事件分发器来达到通信的目的,在C++中使用委托实现。
/** 声明委托类 */
DECLARE_DELEGATE(FFlashBackpackListDelegate);
UCLASS()
class LEARNINGPROJECTV5_API UUI_BackpackListBase : public UUI_Base
{
// 声明成员变量
FFlashBackpackListDelegate FlashBackpackListDelegate;
}
/** 绑定委托类 */
DECLARE_DELEGATE(FFlashBackpackListDelegate);
UCLASS()
class LEARNINGPROJECTV5_API UUI_BackpackListBase : public UUI_Base
{
// 包含声明委托类
UPROPERTY(meta=(BindWidget))
class UUI_BackpackListBase* OutBackpackList;
}
void UUI_BackpackMain::NativeConstruct()
{
Super::NativeConstruct();
// 在需要绑定的时候进行绑定
OutBackpackList->FlashBackpackListDelegate.BindUObject(this, &UUI_BackpackMain::FlashBackpackList);
}
/** 回到声明委托类执行即可 */
if(FlashBackpackListDelegate.IsBound())
{
FlashBackpackListDelegate.Execute();
}
以上,实现了UMG中的事件分发器的效果。
6. 动态创建Widget
// 从指定路径下动态创建Widget,注意路径一定要带.XXXX_C
FString WidgetClassLoadPath = FString(TEXT("/Game/UI/InventoryUI/WBP_InventoryCellBase.WBP_InventoryCellBase_C"));
UClass* ChildWidget = LoadClass<UUserWidget>(NULL, *WidgetClassLoadPath);
if(ChildWidget)
{
UUI_InventoryCellBase* SaveChildWidget = CreateWidget<UUI_InventoryCellBase>(GetWorld(), ChildWidget);
// 设置创建Widget的ItemInfo进行设置
SaveChildWidget->SetItemInfo(BackpackItemInfos[i], ListDragTag);
// 将创建的Widget添加到UniformList中
UniformBackpackList->AddChildToUniformGrid(SaveChildWidget, i,0);
}