[UMG]NativeWidgetHostを継承してカラーピッカーを作る

今回は、NativeWidgetHostというウィジェットを使って、動画のようなカラーピッカーをUMG上で使えるようにする方法を紹介します。

はじめに

SWidgetとUWidget

UE4エディタは多数のUIコンポーネント(ラベル、テキストブロック、ボタン、あるいはそれらを組み合わせたもの)で構築されており、それらUIコンポーネント全てがSWidget(を継承したクラス)です。図1はWidget Reflectorというツールを用いて、エディタを構築するウィジェットを調べたものです。WidgetName一覧にある接頭辞にSがついたクラスは全てSWidgetを継承したクラスであり、UE4エディタがSWidgetを継承したクラスの組み合わせによって構成されていることがわかるかと思います。
図1 Widget Reflector

一方で、図2はUMGのパレットを示したもので、この一覧にあるウィジェットがUWidgetです。UMGを使っていて気づいた方もいらっしゃるかもしれませんが、図2にあるウィジェット、例えばComboBoxやCheckBoxといったウィジェットのデフォルトの外観は、UE4エディタにある同じ機能を持ったウィジェットとまったく同じものです。それもそのはず、UWidgetはSWidgetをUMG向けにラップしたクラスであり、UWidget内部で使われているSWidgetと、UE4エディタで使われているSWidgetは同じものであるためです。
図2 UMGのパレット

NativeWidgetHostとは

UE4のドキュメントには、このように書かれています。
「子スレート ウィジェットを 1 つ格納できるコンテナ ウィジェットです。UMG ウィジェット内部にネイティブ ウィジェットをネスティングすることだけが必要な場合に使用します。」
ここで「子スレートウィジェット」とは、SWidgetを継承したクラスのことを指し、UWidgetとして公開されていないSWidgetをUMG上で使いたい場合に用いる、と説明されています。実は、SWidgetをゲーム中に使うこと自体は、UMGを仲介する必要がありません(参考)。しかし、この方法ではUIデザインはまともにできないため、より扱いやすくするためにUMGに公開する必要があります。そのようなとき、UMGに公開する方法の1つとして、NativeWidgetHostが用意されています。
先程「UWidgetはSWidgetをUMG向けにラップしたもの」と書きましたが、UWidgetとして公開するために最低限必要な実装(Slateの解放、Slateの再構築、パレットカテゴリ)は多くありません。NativeWidgetHostは、それら最低限の処理を実装するためのフレームワークのようなもので、UMG上に公開したいSWidgetをSNewで生成し、SetContentするだけで簡易的にUWidget化できるような機能を持っています。

今回は、このNativeWidgetHostにSColorSpectrumというSWidget継承クラスをホストさせることで、UMG上で簡易的なカラーピッカーを使えるようにすることを目標とします。

実装

まず、Slate, SlateCore, UMGモジュールを追加します。Build.csを次のようにします。
次に、NativeWidgetHostを継承したC++クラスを作成します。図3のように、Show All Classesにチェックを入れた上でNativeWidgetHostを検索し、これを継承したクラス(ColorSpectrumWidgetという名前にします)を作成します。
図3 NativeWidgetHostクラスを継承するクラスを作成

クラスを作成したら、コンストラクタと最低限のプロパティ(ここでは、選択中の色を保持するFLinearColor)を宣言します。.hを次のようにします。
最後に、コンストラクタを定義します。やるべきことは、SNewによってSColorSpectrumを生成し、それをSetContentに与えるだけです。.cppは次のようにします。
SColorSpectrumの引数SelectedColorには、UPROPERTYとして宣言したSelectedColorHSVを返すラムダ式を与えました。これにより、ColorSpectrumWidgetが選択している色(SelectedColorHSV)の位置がカーソルで表示されるようになります。
引数OnValueChangedには、新たに選択された色cをSelectedColorHSVに代入することで、選択中の色の変更をSelectedColorに伝播させるようにします。ところで、色cはHSV式空間の値として表現されており、そのままでは使いにくいのでRGBに変換した値をSelectedColorRGBにセットするようにします。

これで、ColorSpectrumWidgetの実装は終了です。UE4を起動して、UMGのパレットを見てみると、図4のようにColorSpectrumWidgetが追加されています。
図4 ColorSpectrumWidgetを配置した様子

図4のようにImageとColorSpectrumWidgetを配置した後、図5のようにColorSpectrumWidgetを変数化して、Blueprint上で扱えるようにします。
図5 ColorSpectrumWidgetを変数化する

次に、図6のようにImageのColor and Opacityにバインディングを作成します。
図6 関数をバインドする

バインディングを図7のように実装します。これにより、ColorSpectrumWidgetで選択されている色がImageに反映されるようになります。
図7 バインディングの実装

最後に、図8のようにレベルブループリントを実装して実行すると、冒頭の動画のようなカラーピッカーが完成します。
図8 レベルブループリントの実装

おわりに

NativeWidgetHostを使うと、UWidgetとして公開されていないSWidgetを簡単にUMG上に公開することができます。カラーピッカーのような単純なウィジェットであれば、実装も容易でそれなりに有用です。図9は、今回の方法を用いて他のColorPicker系SWidgetを実装した例です。気になるSWidgetを見つけたら、NativeWidgetHostを使って簡易的に実装すれば、表現の幅を広げられると思います。
図9 様々なNativeWidgetHost継承クラス


この記事は次のバージョンで作成されました。
Unreal Editor(4.16.2-3514769+++UE4+Release-4.16)
Microsoft Visual Studio Community 2017 Version 15.1 (26403.7)

コメント

  1. UColorPickerWidget::UColorPickerWidget(const FObjectInitializer& ObjectInitializer):Super(ObjectInitializer)
    {
    TSharedRef colorPicker = SNew(SColorWheel)
    .SelectedColor_Lambda([this]()
    {
    //UE_LOG(LogTemp, Warning, TEXT("HSV %f %f %f"), SelectedColorHSV.R, SelectedColorHSV.G, SelectedColorHSV.B);
    return SelectedColorHSV;
    })
    .OnValueChanged_Lambda([this](FLinearColor c)
    {
    SelectedColorHSV = c;
    //UE_LOG(LogTemp, Warning, TEXT("HSV %f %f %f"), SelectedColorRGB.R, SelectedColorRGB.G, SelectedColorRGB.B);
    UKismetMathLibrary::HSVToRGB_Vector(SelectedColorHSV, SelectedColorRGB);
    });

    SetContent(colorPicker);
    }

    /*
    V 4.21
    I'm not using SColorSpectrum,I'm using SColorWheel。
    SelectedColorRGB :The RGB value is always zero。
    */

    返信削除
    返信
    1. did you ever figure out what you needed to get the color wheel giving out values

      削除
    2. Thank you. I solved the problem.Can I reprint your article to BBS in China?

      削除

コメントを投稿