【UE5】Widget Switcherを使ってタブUIを作る方法
今回はUser Widgetの基本として、タブUIを作る方法を紹介したいと思います。
タブUIを作る手順
ウィジェットブループリントの作成
まずは「ユーザーインターフェース > ウィジェットブループリント」で、ウィジェットブループリントを作成します。

「ユーザーウィジェット」をクリック。

アセット名は「WBP_ItemMenu」としました。

Widgetの配置
「WBP_ItemMenu」を開いてWidgetを以下のように配置します。

Vertical Box
+-- Horizontal Box
| +--Button (Button_0): Is Variable
| | +-- Text Block: "タブ0"
| |
| +--Button (Button_1): Is Variable
| +-- Text Block: "タブ1"
|
+-- Widget Switcher
+--Vertical Box
| +-- Text Block: "武器1"
| +-- Text Block: "武器2"
| +-- Text Block: "武器3"
|
+-- Vertical Box
+-- Text Block: "アイテム1"
+-- Text Block: "アイテム2"
+-- Text Block: "アイテム3"WidgetSwitcherは異なる要素の表示を切り替えるWidgetです。

このWidgetは「Is Variable」をONにして Blueprint からアクセスできるようにします。
またタブ用のボタン(Button_0, Button_1)も「Is Variable」をONにしてクリックイベントを呼び出せるようにします。

クリックイベントの作成
Button_0, Button_1 の詳細タブから「イベント > On Clicked」のところにある「+」ボタンをクリック。

Widget Switcherの「Set Active Widget Index」をそれぞれのクリックイベントから呼び出すようにします。

- Button_0 からの呼び出し時は Indexを "0"
- Button_1 からの呼び出し時は Indexを "1"
動作確認
「WBP_ItemMenu」をレベルブループリントから生成してビューポートに追加。

実行して動作確認。

タブボタンで項目の切り替えができるようになりました。
タブの色の切り替え
タブを切り替えても見た目が変化しないのはわかりにくいので、タブのボタンの背景色 (Background Color) を変えてみます。

実行すると、選択した項目によってタブボタンの色が変化します。

ただこの記述方法では、ボタンや項目数が増えたときに手動でノードを増やす必要があり手間です。
項目が可変になったときにも対応できるようにする方法
やや蛇足ですが、項目を増やしたときにもBPの書き換えなしでタブの切替ができるようにしてみます。
まず、ボタンの通常のクリックイベントには引数が渡せない (正確にはBPでは変数のキャプチャができないので渡せない) ので、C++側でパラメータを渡すため独自のボタンを定義する必要があります。
例えば以下のように実装します。まずはヘッダのコード。
#pragma once
#include "CoreMinimal.h"
#include "Components/Button.h"
#include "CPP_WidgetButton.generated.h"
// 独自の引数付きボタンクリックイベント.
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnButtonClickedEventOneParam, int32, Index);
/**
* タブ用ボタン(UButton継承)
*/
UCLASS()
class TESTTABUI_API UCPP_WidgetButton : public UButton
{
GENERATED_BODY()
public:
// タブ番号
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Tab")
int32 Index = 0;
// int付きクリック
UPROPERTY(BlueprintAssignable, Category="Button|Event", meta=(DisplayName="OnClicked(Int)"))
FOnButtonClickedEventOneParam OnButtonClickedOneParam;
protected:
virtual void OnWidgetRebuilt() override;
virtual void ReleaseSlateResources(bool bReleaseChildren) override;
private:
UFUNCTION()
void HandleClicked(); // 既存OnClickedの受け口
};
続けてcpp側のコード。
// CPP_WidgetButton.cpp
#include "CPP_WidgetButton.h"
void UCPP_WidgetButton::OnWidgetRebuilt()
{
Super::OnWidgetRebuilt();
// 開始時にクリックイベントをバインドしておきます.
OnClicked.AddDynamic(this, &UCPP_WidgetButton::HandleClicked);
}
void UCPP_WidgetButton::ReleaseSlateResources(bool bReleaseChildren)
{
// 念のため解除
OnClicked.RemoveDynamic(this, &UCPP_WidgetButton::HandleClicked);
Super::ReleaseSlateResources(bReleaseChildren);
}
void UCPP_WidgetButton::HandleClicked()
{
// Indexを引数に持つ独自イベントを開始.
OnButtonClickedOneParam.Broadcast(Index);
}
あらかじめOnWidgetRebuilt() でクリックイベントを登録しておき、クリックイベントが発生したら、独自のデリゲート (OnButtonClickedOneParam) を実行するという実装です。
このコードをビルドして、メニュー側のタブボタンを "CPP_WidgetButton" に差し替えます。

そして、タブボタンの親Widgetの Horizontal Box を選択。

名前を「HorizontalBox_Tab」などに変更し、「Is Variable」にチェックして変数化します。

イベントグラフから変数に「TabButtonList」を追加して、型はボタンのオブジェクト参照に設定。

変数の型を配列にします。

そして以下のようにブループリントを組み替えます。

少しややこしいので、流れを整理すると以下のとおりです。


一言で説明すると、クリックイベントに引数は渡せないので、メンバ変数にボタン番号を持たせてクリックイベントを入口に引数付きのデリゲートを実行する、となります。

実行結果は変わらないですが、これでタブボタンを増やしても自動的に(BP側の修正なしで)タブの切替ができるようになります。
以上、タブUIの作り方でした。

