# C++显示UI

# 基本场景

# UI的鼠标事件

下面是鼠标在UI上进入离开,点击事件的判定:

//================================头文件===================================
#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "MyTestUserWidget.generated.h"

/**
 * 
 */
UCLASS()
class TESTLEARN20211220_API UMyTestUserWidget : public UUserWidget
{
    GENERATED_BODY()
public:
    virtual void NativeOnMouseEnter(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override;
    virtual void NativeOnMouseLeave(const FPointerEvent& InMouseEvent) override;
    virtual FReply NativeOnMouseButtonDown( const FGeometry& InGeometry, const FPointerEvent& InMouseEvent ) override;
    virtual FReply NativeOnMouseButtonUp( const FGeometry& InGeometry, const FPointerEvent& InMouseEvent ) override;	
};

//================================cpp文件===================================
#include "MyTestUserWidget.h"

void UMyTestUserWidget::NativeOnMouseEnter(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent)
{
    UE_LOG(LogTemp,Warning,TEXT("on mouse enter!"));
}

void UMyTestUserWidget::NativeOnMouseLeave(const FPointerEvent& InMouseEvent)
{
    UE_LOG(LogTemp,Warning,TEXT("on mouse leave!"));
}

FReply UMyTestUserWidget::NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent)
{
    UE_LOG(LogTemp,Warning,TEXT("on mouse down!"));
    return FReply::Handled();
}

FReply UMyTestUserWidget::NativeOnMouseButtonUp(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent)
{
    UE_LOG(LogTemp,Warning,TEXT("on mouse up!"));
    return FReply::Handled();
}
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

注意:

  1. Actor类的蓝图有一个BlockInput,如果把这个勾选,是无法进行操作了。
  2. 如果要3DUI也要有这些事件,需要勾选Interaction->Receive Hardware Input。

# UI初始化

关于UI的初始化有几个方法:

  • virtual void NativeOnInitialized() override;
    • 在游戏运行中的非模板实例调用,因为Construct/Destruct适用于底层的Slate,每个UserWidget只调用一次。如果你有只做一次的事,比如绑定BindWidget属性的事件上的回调函数,可以在这里做。
  • virtual void NativePreConstruct() override;
    • 被游戏和编辑器调用,允许用户运行初始化脚本来让控件在编辑器Designer中有更好的预览,同样在游戏运行时它也会在调用。
    • 这个仅用于使用本地的数据来进行表面的更新,你不能安全地获取任何游戏相关的状态,如果你调用了并不打算在编辑器下运行的逻辑,你会直接把editor搞崩溃。
    • 在这个事件中如果使用蓝图的代码来保存资产,这会直接导致崩溃,你可以在Editor Preferences中关闭PreConstruct。
  • virtual void NativeConstruct() override;
    • 在底层slate被创建后调用,这取决于slate对象如何被用的。这个事件会因为UserWidget增加移除到视口上而被调用多次,如果你需要called-once-when-created事件,使用OnInitialized。
  • virtual void NativeDestruct() override;
    • 当一个UserWidget不再被引用时,这会导致slate资源被销毁,就像Construct事件被调用多次。
  1. 在创建UserWidget时,调用NativeOnInitialized。
  2. 在RemoveFromParent时,调用NativeDestruct。
  3. 在AddToViewport时,调用NativePreConstruct和NativeConstruct。

# 场景应用

用C++显示一个UI,并控制该UI显示文字。

# 操作步骤

  1. 创建UIGameInstance.cpp:

    //===========================UIGameInstance.h=======================
    // Fill out your copyright notice in the Description page of Project Settings.  
    #pragma once
    
    #include "CoreMinimal.h"
    #include "Engine/GameInstance.h"
    #include "MyUserWidget.h"
    #include "UIGameInstance.generated.h"
    
    /**
     * 
     */
    UCLASS()
    class TEST20210310_API UUIGameInstance : public UGameInstance
    {
        GENERATED_BODY()
        UUIGameInstance();
    
        void DelayFunction();
    
        FTimerHandle myTimerHandle;
        TSubclassOf<class UMyUserWidget> MenuClassSource;
        UMyUserWidget* Menu;
        virtual void Init();
        
    };
    
    //===================UIGameInstance.cpp=====================
    // Fill out your copyright notice in the Description page of Project Settings.
    #include "UIGameInstance.h"
    UUIGameInstance::UUIGameInstance() {
        ConstructorHelpers::FClassFinder<UMyUserWidget> MenuClassFinder(TEXT("/Game/TestUI"));
        MenuClassSource = MenuClassFinder.Class;
    
    }
    
    void UUIGameInstance::DelayFunction()
    {
        Menu = CreateWidget<UMyUserWidget>(GetWorld(), MenuClassSource);
        if (Menu) {
            Menu->SetupUI();
            GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Run Init Progress!"));
            //Menu->SetVisibility(ESlateVisibility::Visible);
            /*APlayerController* PlayerController = GetWorld()->GetFirstPlayerController();
            FInputModeUIOnly InputModeData;
            InputModeData.SetWidgetToFocus(Menu->TakeWidget());
            InputModeData.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);
            PlayerController->SetInputMode(InputModeData);
            PlayerController->bShowMouseCursor = true;*/
        }
    }
    
    void UUIGameInstance::Init()
    {
       GetWorld()->GetTimerManager().SetTimer(myTimerHandle, this, &UUIGameInstance::DelayFunction, 3.0f, false);
    }
    
    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
  2. C++创建UserWidget:

    //=========================MyUserWidget.h==========================
    #pragma once
    
    #include "CoreMinimal.h"
    #include "Blueprint/UserWidget.h"
    #include "Runtime/UMG/Public/Components/TextBlock.h"
    #include "MyUserWidget.generated.h"
    
    /**
     * 
     */
    UCLASS()
    class TEST20210310_API UMyUserWidget : public UUserWidget
    {
        GENERATED_BODY()
    
    public:
        void SetupUI();
    
        UPROPERTY(meta = (BindWidget))
        class UTextBlock* ItemTitle;
        
    };
    
    
    //========================MyUserWidget.cpp=======================
    #include "MyUserWidget.h"
    
    void UMyUserWidget::SetupUI()
    {
        this->AddToViewport();
        ItemTitle->SetText(FText::FromString(TEXT("谢谢")));
        //ItemTitle->SetText(NSLOCTEXT("MyOtherNamespace", "HelloWorld","лл"));
    }
    
    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
  3. 在UE4中创建蓝图继承MyUserWidget,并创建一个名为"ItemTitle"的TextBlock。