Proportional Scrollbar Handles Demo

I admit that I’ve struggled with scrollbars since the Crossbasic days: Specifically, how to get the scrollbar handle to be proportional to the content height. Facing the problem again, I didn’t find the ideal solution in the forums, so I put together a simple demo project:

The code:

Var contentHeight As Double = Canvas1.Height
Var visibleFractionOfContentHeight As Double = contentHeight / Me.Height

// Make the scrollbar handle proportional
Scrollbar1.MaximumValue = Ceil((visibleFractionOfContentHeight - 1) * 20) // 20 is magic number that will put the scrollbar at 50%

// Scroll the content
Canvas1.Top = (Me.Height - contentHeight) * Scrollbar1.Value / Scrollbar1.MaximumValue

“20” is a magic number. Would be smoother if .MaximumValue were floating point rather than an Integer, but it works. And I’m open to better solutions.

More output:

4 Likes

Here’s a project that has a DesktopScrollbar subclass called ProportionalDesktopScrollbar.

It has one new function, GetContentOffset, that takes the content size and visible size, computes the proportional handle size, and returns the content offset:

Public Function GetContentOffset(contentSize as Double, visibleSize as Double) As Double
  Var visibleFractionOfContentHeight As Double = contentSize / visibleSize
  
  // Make the handle proportional
  Var maxValue As Double = Ceil((visibleFractionOfContentHeight - 1) * 20) // 20 is magic number that will put a scrollbar at 50%
  Me.MaximumValue = maxValue
  
  If maxValue = 0 Then Return 0
  
  // Return the scroll offset
  Return (visibleSize - contentSize) * (Me.Value / Me.MaximumValue)
  
End Function

Call this when resizing the window or when the scrollbar’s value is changed. In the demo project:

Canvas1.Top = ScrollBar1.GetContentOffset(Canvas1.Height, Me.Height)

The class will work with horizontal or vertical scrollbars.

3 Likes

Bug fix: 20 is not a magic number—it’s the PageStep value. Using a high PageStep value will increase the granularity of the scrollbar.

Public Function GetContentOffset(contentSize as Double, visibleSize as Double) As Double
  Var visibleFractionOfContentHeight As Double = contentSize / visibleSize
  
  // Make the handle proportional
  Var maxValue As Double = Ceil((visibleFractionOfContentHeight - 1) * Me.PageStep) // Higher PageStep values offer more granularity in the scrollbar's position
  Me.MaximumValue = maxValue
  
  If maxValue = 0 Then Return 0
  
  // Return the scroll offset
  Return (visibleSize - contentSize) * (Me.Value / Me.MaximumValue)
  
End Function

I’ve updated both of the linked projects, above.

3 Likes

Is there any way to change the width of a scroolbar on a webview?

Sorry; I haven’t done any work with XOJO web apps yet.