对话框
对话框
对话框
用户界面用于向用户提示信息进行确认的对话框. 该部分内容主要包含在CommomGame插件里面.
对话框可能结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/** Possible results from a dialog */
/** 对话可能出现的结果 */
UENUM(BlueprintType)
enum class ECommonMessagingResult : uint8
{
/** The "yes" button was pressed */
/** “是”按钮已被按下 */
Confirmed,
/** The "no" button was pressed */
/** “拒绝”按钮已被按下 */
Declined,
/** The "ignore/cancel" button was pressed */
/** “忽略/取消”按钮已被按下 */
Cancelled,
/** The dialog was explicitly killed (no user input) */
/** 该对话框已被明确关闭(未收到用户输入) */
Killed,
Unknown UMETA(Hidden)
};
DECLARE_DELEGATE_OneParam(FCommonMessagingResultDelegate, ECommonMessagingResult /* Result */);
对话框子系统
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
UCLASS(MinimalAPI, config = Game)
class UCommonMessagingSubsystem : public ULocalPlayerSubsystem
{
GENERATED_BODY()
public:
UCommonMessagingSubsystem() { }
// 无作用
UE_API virtual void Initialize(FSubsystemCollectionBase& Collection) override;
// 无作用
UE_API virtual void Deinitialize() override;
// 避免重复创建
UE_API virtual bool ShouldCreateSubsystem(UObject* Outer) const override;
// 仅接口未实现
UE_API virtual void ShowConfirmation(UCommonGameDialogDescriptor* DialogDescriptor, FCommonMessagingResultDelegate ResultCallback = FCommonMessagingResultDelegate());
// 仅接口未实现
UE_API virtual void ShowError(UCommonGameDialogDescriptor* DialogDescriptor, FCommonMessagingResultDelegate ResultCallback = FCommonMessagingResultDelegate());
private:
};
游戏实例的信息注册处理登录用户信息
1
2
3
4
5
6
7
8
9
10
11
12
13
void UCommonGameInstance::HandleSystemMessage(FGameplayTag MessageType, FText Title, FText Message)
{
ULocalPlayer* FirstPlayer = GetFirstGamePlayer();
// Forward severe ones to the error dialog for the first player
// 将严重错误信息转发给第一个玩家的错误对话框中显示
if (FirstPlayer && MessageType.MatchesTag(FCommonUserTags::SystemMessage_Error))
{
if (UCommonMessagingSubsystem* Messaging = FirstPlayer->GetSubsystem<UCommonMessagingSubsystem>())
{
Messaging->ShowError(UCommonGameDialogDescriptor::CreateConfirmationOk(Title, Message));//此处无需回调
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void UCommonGameInstance::Init()
{
Super::Init();
// After subsystems are initialized, hook them together
// 在子系统初始化完成后,将它们连接起来
FGameplayTagContainer PlatformTraits = ICommonUIModule::GetSettings().GetPlatformTraits();
UCommonUserSubsystem* UserSubsystem = GetSubsystem<UCommonUserSubsystem>();
if (ensure(UserSubsystem))
{
UserSubsystem->SetTraitTags(PlatformTraits);
UserSubsystem->OnHandleSystemMessage.AddDynamic(this, &UCommonGameInstance::HandleSystemMessage);
UserSubsystem->OnUserPrivilegeChanged.AddDynamic(this, &UCommonGameInstance::HandlePrivilegeChanged);
UserSubsystem->OnUserInitializeComplete.AddDynamic(this, &UCommonGameInstance::HandlerUserInitialized);
}
UCommonSessionSubsystem* SessionSubsystem = GetSubsystem<UCommonSessionSubsystem>();
if (ensure(SessionSubsystem))
{
SessionSubsystem->OnUserRequestedSessionEvent.AddUObject(this, &UCommonGameInstance::OnUserRequestedSession);
SessionSubsystem->OnDestroySessionRequestedEvent.AddUObject(this, &UCommonGameInstance::OnDestroySessionRequested);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
void UCommonUserSubsystem::HandleUserInitializeFailed(FCommonUserInitializeParams Params, FText Error)
{
UCommonUserInfo* LocalUserInfo = ModifyInfo(GetUserInfoForLocalPlayerIndex(Params.LocalPlayerIndex));
if (!LocalUserInfo)
{
// The user info was reset since this was scheduled
return;
}
UE_LOG(LogCommonUser, Warning, TEXT("TryToInitializeUser %d failed with error %s"), LocalUserInfo->LocalPlayerIndex, *Error.ToString());
// If state is wrong, abort as we might have gotten canceled
if (!ensure(LocalUserInfo->IsDoingLogin()))
{
return;
}
// If initial login failed or we ended up totally logged out, set to complete failure
ELoginStatusType NewStatus = GetLocalUserLoginStatus(Params.PlatformUser, Params.OnlineContext);
if (NewStatus == ELoginStatusType::NotLoggedIn || LocalUserInfo->InitializationState == ECommonUserInitializationState::DoingInitialLogin)
{
LocalUserInfo->InitializationState = ECommonUserInitializationState::FailedtoLogin;
}
else
{
LocalUserInfo->InitializationState = ECommonUserInitializationState::LoggedInLocalOnly;
}
FText TitleText = NSLOCTEXT("CommonUser", "LoginFailedTitle", "Login Failure");
if (!Params.bSuppressLoginErrors)
{
SendSystemMessage(FCommonUserTags::SystemMessage_Error_InitializeLocalPlayerFailed, TitleText, Error);
}
// Call callbacks
Params.OnUserInitializeComplete.ExecuteIfBound(LocalUserInfo, false, Error, Params.RequestedPrivilege, Params.OnlineContext);
OnUserInitializeComplete.Broadcast(LocalUserInfo, false, Error, Params.RequestedPrivilege, Params.OnlineContext);
}
UCommonGameDialogDescriptor(对话框描述器)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
UCLASS(MinimalAPI)
class UCommonGameDialogDescriptor : public UObject
{
GENERATED_BODY()
public:
static UE_API UCommonGameDialogDescriptor* CreateConfirmationOk(const FText& Header, const FText& Body);
static UE_API UCommonGameDialogDescriptor* CreateConfirmationOkCancel(const FText& Header, const FText& Body);
static UE_API UCommonGameDialogDescriptor* CreateConfirmationYesNo(const FText& Header, const FText& Body);
static UE_API UCommonGameDialogDescriptor* CreateConfirmationYesNoCancel(const FText& Header, const FText& Body);
public:
/** The header of the message to display */
/** 显示的消息的标题 */
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FText Header;
/** The body of the message to display */
/** 将要显示的消息主体 */
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FText Body;
/** The confirm button's input action to use. */
/** 确认按钮的输入操作方式。*/
UPROPERTY(BlueprintReadWrite)
TArray<FConfirmationDialogAction> ButtonActions;
};
以最复杂的实现为例,存在确认,拒绝,取消这三个操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
UCommonGameDialogDescriptor* UCommonGameDialogDescriptor::CreateConfirmationYesNoCancel(const FText& Header, const FText& Body)
{
UCommonGameDialogDescriptor* Descriptor = NewObject<UCommonGameDialogDescriptor>();
Descriptor->Header = Header;
Descriptor->Body = Body;
FConfirmationDialogAction ConfirmAction;
ConfirmAction.Result = ECommonMessagingResult::Confirmed;
ConfirmAction.OptionalDisplayText = LOCTEXT("Yes", "Yes");
FConfirmationDialogAction DeclineAction;
DeclineAction.Result = ECommonMessagingResult::Declined;
DeclineAction.OptionalDisplayText = LOCTEXT("No", "No");
FConfirmationDialogAction CancelAction;
CancelAction.Result = ECommonMessagingResult::Cancelled;
CancelAction.OptionalDisplayText = LOCTEXT("Cancel", "Cancel");
Descriptor->ButtonActions.Add(ConfirmAction);
Descriptor->ButtonActions.Add(DeclineAction);
Descriptor->ButtonActions.Add(CancelAction);
return Descriptor;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
USTRUCT(BlueprintType)
struct FConfirmationDialogAction
{
GENERATED_BODY()
public:
/** Required: The dialog option to provide. */
/** 必填项:需提供的对话选项。*/
UPROPERTY(EditAnywhere, BlueprintReadWrite)
ECommonMessagingResult Result = ECommonMessagingResult::Unknown;
/** Optional: Display Text to use instead of the action name associated with the result. */
/** (可选):显示用于替代与结果相关联的操作名称的文本内容。*/
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FText OptionalDisplayText;
bool operator==(const FConfirmationDialogAction& Other) const
{
return Result == Other.Result &&
OptionalDisplayText.EqualTo(Other.OptionalDisplayText);
}
};
实际运用
蓝图函数节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 显示"Yes/No"确认对话框的异步操作
UAsyncAction_ShowConfirmation* UAsyncAction_ShowConfirmation::ShowConfirmationYesNo(UObject* InWorldContextObject, FText Title, FText Message)
{
UAsyncAction_ShowConfirmation* Action = NewObject<UAsyncAction_ShowConfirmation>();
Action->WorldContextObject = InWorldContextObject;
Action->Descriptor = UCommonGameDialogDescriptor::CreateConfirmationYesNo(Title, Message);
Action->RegisterWithGameInstance(InWorldContextObject);
return Action;
}
// 显示"Ok/Cancel"确认对话框的异步操作
UAsyncAction_ShowConfirmation* UAsyncAction_ShowConfirmation::ShowConfirmationOkCancel(UObject* InWorldContextObject, FText Title, FText Message)
{
UAsyncAction_ShowConfirmation* Action = NewObject<UAsyncAction_ShowConfirmation>();
Action->WorldContextObject = InWorldContextObject;
Action->Descriptor = UCommonGameDialogDescriptor::CreateConfirmationOkCancel(Title, Message);
Action->RegisterWithGameInstance(InWorldContextObject);
return Action;
}
// 显示自定义确认对话框的异步操作
UAsyncAction_ShowConfirmation* UAsyncAction_ShowConfirmation::ShowConfirmationCustom(UObject* InWorldContextObject, UCommonGameDialogDescriptor* Descriptor)
{
UAsyncAction_ShowConfirmation* Action = NewObject<UAsyncAction_ShowConfirmation>();
Action->WorldContextObject = InWorldContextObject;
Action->Descriptor = Descriptor;
Action->RegisterWithGameInstance(InWorldContextObject);
return Action;
}
转发对话框描述器信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
UCLASS()
class ULyraUIMessaging : public UCommonMessagingSubsystem
{
GENERATED_BODY()
public:
ULyraUIMessaging() { }
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
virtual void ShowConfirmation(UCommonGameDialogDescriptor* DialogDescriptor, FCommonMessagingResultDelegate ResultCallback = FCommonMessagingResultDelegate()) override;
virtual void ShowError(UCommonGameDialogDescriptor* DialogDescriptor, FCommonMessagingResultDelegate ResultCallback = FCommonMessagingResultDelegate()) override;
private:
UPROPERTY()
TSubclassOf<UCommonGameDialog> ConfirmationDialogClassPtr;
UPROPERTY()
TSubclassOf<UCommonGameDialog> ErrorDialogClassPtr;
// 确认确定框的控件类
UPROPERTY(config)
TSoftClassPtr<UCommonGameDialog> ConfirmationDialogClass;
// 错误对话框的控件类
UPROPERTY(config)
TSoftClassPtr<UCommonGameDialog> ErrorDialogClass;
};
控件类需配置才能正常显示 DefaultGame.ini
1
2
3
4
5
[/Script/LyraGame.LyraUIMessaging]
; 确认对话框
ConfirmationDialogClass=/Game/UI/Foundation/Dialogs/W_ConfirmationDefault.W_ConfirmationDefault_C
; 错误对话框
ErrorDialogClass=/Game/UI/Foundation/Dialogs/W_ConfirmationError.W_ConfirmationError_C
1
2
3
4
5
6
7
8
9
10
11
12
void ULyraUIMessaging::ShowConfirmation(UCommonGameDialogDescriptor* DialogDescriptor, FCommonMessagingResultDelegate ResultCallback)
{
if (UCommonLocalPlayer* LocalPlayer = GetLocalPlayer<UCommonLocalPlayer>())
{
if (UPrimaryGameLayout* RootLayout = LocalPlayer->GetRootUILayout())
{
RootLayout->PushWidgetToLayerStack<UCommonGameDialog>(TAG_UI_LAYER_MODAL, ConfirmationDialogClassPtr, [DialogDescriptor, ResultCallback](UCommonGameDialog& Dialog) {
Dialog.SetupDialog(DialogDescriptor, ResultCallback);
});
}
}
}
生成对话框
对话框基类
1
2
3
4
5
6
7
8
9
10
11
12
UCLASS(MinimalAPI, Abstract)
class UCommonGameDialog : public UCommonActivatableWidget
{
GENERATED_BODY()
public:
// 无
UE_API UCommonGameDialog();
// 接口
UE_API virtual void SetupDialog(UCommonGameDialogDescriptor* Descriptor, FCommonMessagingResultDelegate ResultCallback);
// 接口
UE_API virtual void KillDialog();
};
继承于对话框基类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/**
* 用于接收确认信息的对话框 需要蓝图进行绑定控件
*/
UCLASS(Abstract, BlueprintType, Blueprintable)
class ULyraConfirmationScreen : public UCommonGameDialog
{
GENERATED_BODY()
public:
// 根据描述器建立对话框
virtual void SetupDialog(UCommonGameDialogDescriptor* Descriptor, FCommonMessagingResultDelegate ResultCallback) override;
// 无
virtual void KillDialog() override;
protected:
// 绑定退出按钮
virtual void NativeOnInitialized() override;
// 关闭窗口 并推送对话框选择的结果
virtual void CloseConfirmationWindow(ECommonMessagingResult Result);
#if WITH_EDITOR
// 编辑器接口 确保取消行为有效
virtual void ValidateCompiledDefaults(IWidgetCompilerLog& CompileLog) const override;
#endif
private:
// 背景的退出按钮
UFUNCTION()
FEventReply HandleTapToCloseZoneMouseButtonDown(FGeometry MyGeometry, const FPointerEvent& MouseEvent);
// 传递给蓝图的后续执行引脚对应的对话框结果
FCommonMessagingResultDelegate OnResultCallback;
private:
// 标题
UPROPERTY(Meta = (BindWidget))
TObjectPtr<UCommonTextBlock> Text_Title;
// 描述
UPROPERTY(Meta = (BindWidget))
TObjectPtr<UCommonRichTextBlock> RichText_Description;
// 按钮的容器 这里需要指定实例化的子类
UPROPERTY(Meta = (BindWidget))
TObjectPtr<UDynamicEntryBox> EntryBox_Buttons;
// 关闭案例
UPROPERTY(Meta = (BindWidget))
TObjectPtr<UCommonBorder> Border_TapToCloseZone;
// 取消的行为
UPROPERTY(EditDefaultsOnly, meta = (RowType = "/Script/CommonUI.CommonInputActionDataBase"))
FDataTableRowHandle CancelAction;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// Setup the confirmation dialog with descriptor and callback
// 使用描述符和回调设置确认对话框
void ULyraConfirmationScreen::SetupDialog(UCommonGameDialogDescriptor* Descriptor, FCommonMessagingResultDelegate ResultCallback)
{
Super::SetupDialog(Descriptor, ResultCallback);
// Set dialog title and body text from descriptor
// 从描述符设置对话框标题和正文文本
Text_Title->SetText(Descriptor->Header);
RichText_Description->SetText(Descriptor->Body);
// Clear existing buttons and their click handlers
// 清除现有按钮及其点击处理程序
EntryBox_Buttons->Reset<ULyraButtonBase>([](ULyraButtonBase& Button)
{
Button.OnClicked().Clear();
});
// Create buttons for each action in the descriptor
// 为描述符中的每个操作创建按钮
for (const FConfirmationDialogAction& Action : Descriptor->ButtonActions)
{
FDataTableRowHandle ActionRow;
// Determine input action based on result type
// 根据结果类型确定输入操作
switch (Action.Result)
{
case ECommonMessagingResult::Confirmed:
ActionRow = ICommonInputModule::GetSettings().GetDefaultClickAction();
break;
case ECommonMessagingResult::Declined:
ActionRow = ICommonInputModule::GetSettings().GetDefaultBackAction();
break;
case ECommonMessagingResult::Cancelled:
ActionRow = CancelAction;
break;
default:
ensure(false);
continue;
}
// Create button and configure its properties
// 创建按钮并配置其属性
ULyraButtonBase* Button = EntryBox_Buttons->CreateEntry<ULyraButtonBase>();
Button->SetTriggeringInputAction(ActionRow);
// Bind click event to close confirmation with specific result
// 绑定点击事件以特定结果关闭确认
Button->OnClicked().AddUObject(this, &ThisClass::CloseConfirmationWindow, Action.Result);
Button->SetButtonText(Action.OptionalDisplayText);
}
// Store the result callback for later execution
// 存储结果回调以供稍后执行
OnResultCallback = ResultCallback;
}
本文由作者按照 CC BY 4.0 进行授权
