3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【UE】リストの項目をドラッグ操作で入れ替える

Posted at

初めに

WebUIやアプリケーションのUIでもよくあるリストの項目をドラッグで入れ替える操作をUEのウィジェットでやりたいなと思ったのがきっかけだったのですが、UEのScrollBoxには並び替えの機能はないので独自で標準機能を組み合わせて実現してみました。他の方法やもっと効率の良い実装方法はあるかもしれませんが、実装例の1つと考えていただければ幸いです。

環境情報

Windows 11
UE 5.3.2

実装方法

大まかな実装方法としてはマウスがホバーしているScrollBoxの子要素をモニターしておき、ドラッグしてマウスを離したタイミングで対象の子要素がマウスを離した時にホバーしている子要素の上になるようにScrollBox内の子要素一度削除して順番にScrollBoxに追加していきます。
説明簡略のためにI/Fなどは使用せず全てハード参照していますが悪しからず。

①ScrollBoxの子要素Widgetを作成する

まずはScrollBoxに子要素として追加するWidgetを作成します(WBP_Slot)
中身の構成は何でもよいのですが、一番シンプルにBorderにTextBlockを入れたものを用意しました。

image.png

生成時に文字列を渡せるようにText変数を用意してExpose on Spawnにしておきます。

image.png

②リストとして表示するWidgetを作成する

ScrollBoxを保持しているWidgetを作成します(WBP_List)
大きさの調整のためにScaleBoxに入れてありますがここはご自身のプロジェクトに合うようにしてください。

image.png

EventGraphの方でAddSlotというカスタムイベントを用意します。
ここでWBP_Slotを必要分生成してScaleBoxに追加しています。
並び替えを管理するためにSlotsというString型の配列も用意しておきます。

image.png

WBP_ListをAdd to Viewportして実行するとこんな感じです

image.png

③WBP_Slotにイベントを追加する

Event DispatchersにOnSelected、OnMouseHovered、OnMouseUnhoveredという名前を付けてイベントを追加します。
OnSelectedとOnMouseHoveredには引数として自分自身(WBP_Slot)を渡すようにします。

image.png
image.png

FunctionsのOverrideからOnMouseButtonDown、OnMouseEnter、OnMouseLeaveを追加します。

image.png

追加したOnMouseButtonDown、OnMouseEnter、OnMouseLeaveにはそれぞれ先ほど作成したOnSelected、OnMouseHovered、OnMouseUnhoveredを呼ぶようにノードをつなぎます。

image.png
image.png

④WBP_ListでWBP_Slotのイベントを購読する

先ほど作成したAddSlotイベントの中でWBP_Slotを生成した後にイベントを購読しておきます。
この時に変数としてSelectedSlot(WBP_Slot)とHoveredSlot(WBP_Slot)を用意します。
OnSelectedイベントで引数をSelectedSlotに値を格納し、
OnMouseHoveredイベントで引数をHoveredSlotに格納、OnMouseUnhoveredで初期化しておきます。
SelectedSlotで現在どのSlotが選択状態か管理し、HoveredSlotで現在どのSlotにホバーが当たっているか管理します。

image.png

⑤WBP_Slotで選択時、ホバー時の色を設定しておく

この手順は見やすくするためのものなので読み飛ばしてしまっても大丈夫です。

WBP_SlotのOnMouseButtonDownの中でBorderとTextBlockの色を変えておき、自分自身が選択状態であるかを判定するためにIsSelectedというBool値を追加します。

image.png

また、他のSlotが選択された時に色を元に戻せるようにDeselectイベントを作成しておきます。

image.png

ホバー時の色を変更するためにOnMouseEnterイベントで選択状態でなければ色を変更し、OnMouseLeaveイベントで選択状態でなければ色を戻します。
image.png

WBP_Listの方でNotifySelectedSlotChangedイベントを作成して、現在選択中のSlot以外のSlotのDeselectを呼び出します。
OnSelectedイベントの最後でNotifySelectedSlotChangedを呼び出します。

image.png

実際に動かしてみるとこんな感じです
ダウンロード.gif

⑥WBP_Listで並び替え処理を実装する

まずはScrollBoxの中身を全て削除した後で再度並び替え後のSlotを生成してScrollBoxに追加する処理を実装します。
RefleshListというイベントを作成しました。ScrollBoxの中身を削除したあとでソート済みのSlots配列を使って順番にAddSlotを呼び出します。

image.png

次にSlots配列の中身を並び替える処理を実装します。
ExecuteSortというイベントを作成しました。SelectedSlotのTextと同じものをSlotsからRemoveを行い、HoveredSlotのTextと同じものをSlotsからFindし、見つけたIndexにSelectedSlotのTextをSlotsにInsertして先ほど作成したRefleshListを呼び出します。そうすることでHoveredSlotsの上にSelectedSlotが表示されるようになります。

image.png

⑦並び替えを実行するか判定する

マウスのドラッグによって並び替えを行いますが、UEではマウスをドラッグしていることを起点にするイベントは存在しません。なのでマウスのクリックを起点に一定時間マウスがクリックされた状態であった場合に入れ替えそうさを行うようにしていきます。

マウスが離された時に入れ替えを行うかどうかの判定をIsSortModeというBool値で管理しておきます。
また、IsSortModeをtrueにするためのイベントを用意しておきます(ChangeToSortMode)。

image.png

次にマウスのクリックを検知した際に入れ替えの判定を開始するイベントを追加します。
OnMousePressedというイベントを作成しました。SetTimerByFunctionNameを使って先ほど作成したChangeToSortModeを0.15秒後に実行するようにしています。

image.png

また、マウスを離した時の処理を追加します。
OnMouseReleasedというイベントを作成しました。ClearTimerByFunctionNameを呼んで0.15秒以内にマウスが離された場合はChangeToSortModeイベントを実行しないようにします。0.15秒が経過してIsSortModeがTrueになっている場合はExecuteSortを実行します。

image.png

SetTimerByFunctionNameとClearTimerByFunctionNameでタイマー管理をすることでSlotを選択だけするためにクリックしたときにも入れ替えが実行されることを防いでいます。

作成したOnMousePressedイベントはWBP_SlotのOnSelectedイベントを購読している部分で呼び出し、
OnMouseReleasedイベントはWBP_ListでOnMouseButtonUpをOverrideで追加してその中で呼びます。

image.png
image.png

これでSlotの入れ替えができるようになりました。

今回はUnrealEngineのThirdPersonサンプルを使っていてViewPortに貼り付けて実装していたため、ウィジェットに対してマウスでクリックしている最中にホバーも検知できるようにSetInputModeUIOnlyを設定しました(LevelBlueprintでやっちゃってます)。
プロジェクトやUIの作り方によっては不要な設定ですが一応コードも貼っておきます。
image.png

実際に動かしている様子がこちらです。
sort.gif

以上で基本的なリストの入れ替えの実装は完了です。
この実装はホバーしているSlotの上に並び替えるものなので一番下には並び替えることはできません。
一番最後にダミーのSlotを追加するか、入れ替え先を選択するためのBorderなどで各Slotを挟む構造にすれば柔軟に並び替えを行うことができるので(今回は説明簡略のため省略しました)、ご自身の実現したいUIに合わせて試してみてください。

image.png

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?