Quick and Dirty Custom Scrollbar for the built-in Scrollbox UMG Widget

Categories // Action Arcade Wrestling: Development in Action

A rundown of how we setup a custom Scrollbar in UMG

As you may already know, UMG provides a built-in Scrollbox widget for easily displaying scrollable content. This widget handles all of the hard bits and gives you the ability to, mostly; customize its look to your liking. However, the scrollbar behavior is set in stone from UMGs side of things. Meaning you cannot have a scrollbar that has a constant size and does not change opacity on rollover.

NOTE: All Images shown here are WORK-IN-PROGRESS and do not represent the final product

But, this was exactly the behavior we needed!
Short of going in and modifying Slate code, there was no way to achieve this and we needed something quick and dirty to test the concept. I had an idea of simply using a Slider widget turned 90 degrees as the scrollbar and somehow have that drive the Scrollbox’s position and have the slider driven by the Scrollbox when scrolling with the mouse wheel. The latter is simple, or so I thought; Scrollbox widget has a GetScrollOffset node, which returns a float of the offset the Scrollbox is on. All we need to do now is map that value into the sliders 0 – 1 range, but we do not yet know the max scroll offset of our Scrollbox and there is no way to retrieve it… What to do? Well, there is a node called ScrollToEnd so let us see how it finds the “end” offset. Looking at UScrollBox, we see it forwards the call to the Slate Scrollbox:

Looking at the Slate Scrollbox, we see it simply setting a bool for later use during Tick:
Now, let us see what it does during Tick:

Looking at that, the Scrollbox looks up its Panel Geometry followed by that Panel’s desired size. GetScrollComponentFromVector() simply checks what Orientation the Scrollbox is set to and returns either the X or Y component. The bit that calculates the actual end scroll offset, simply subtracts the Scroll Panels Geometry size from its desired size. Simple! Nevertheless, there is no “GetEndScrollOffset” node! How do we reproduce this in BP?
Here is how I set it up, and it is not very pretty:
This cluster of nodes that execute on Initialize calculate the Scrollboxes Height and store it for later use during the SliderValuerChanged event (shown above) and in the GetSliderValue function (shown below).

The Initialize nodes replicate the code in SScrollBox::Tick() function, but with a few tweaks like taking each elements padding into account. Once we have the Scrollbox Height, we can use it to drive the Slider and have it and the Scrollbox interact through this helper Object. Note: I am assuming that everything is in the vertical orientation here hence using only the Y components of Size.
It is far from perfect, but gets the job done! Here is how we hook it up in a Menu Screen:
We create the helper object that holds all of the calculation logic and call its Initialize event after a small delay. The delay is to make sure all of the widgets are constructed prior to grabbing their size in the Initialize call.
At this point, we only need to hook up two things: the OnValueChanged event of our Slider and the Get_ScrollBoxSlider_Value. The former will tell our Scrollbox to scroll based on where our Slider is, like so:
The latter will tell the Slider to move to a position based on the Scrollboxes offset when scrolling using a mouse wheel, like so:
The result looks like this:
I hope that UMG will soon make this a simpler process by adding in an option to switch between different scrollbar behaviors. Nick Darnell, if you are reading this, would love to hear your thoughts!

I actually began setting this whole thing up as a UserWidget to make it a bit more convenient and portable. However, it turns out the UserWidgets cannot have children added to them via the Editor. So dragging in Widgets does not work. At least not yet. Something I would love to see added to UMG soon; it would add a great amount of flexibility and convenience to creating custom behavior!

Happy to answer any questions and if you know of an even better way to achieve something like this, do let me know.

Leave a comment

Please login to leave a comment. Optional login below.

Twitter Feed

No tweets found.