ListBox scroll wheel moves by fractional rows

Depending on the size of a Listbox (if the application allows resizing the listbox to arbitrary amounts), scrolling with the scroll wheel will cause the list to move by an amount different from the height of a row. This means that text will drift vertically during a scroll wheel operation.

This behavior is visible in the Juce demo, on the Fonts and Text tab. Just run the demo, switch to Fonts and Text, then scroll the list with the wheel. The demo window comes up at a size that causes that list to move in fractional row heights by default.

To see it clearly, add these two lines to the bottom of paintListBoxItem


void paintListBoxItem (int rowNumber,
                       Graphics& g,
                       int width, int height,
                       bool rowIsSelected)

    g.setColour (Colours::black);
    g.drawRect (0, height-1, width, 1);

So what?

If you have a big list and you’re trying to find something in a particular column is is quite distracting especially in the middle of a live performance.

I spent some time digging into it and I figured out that it is the Viewport which is doing the dirty work. So I’m thinking of a simple addition to the Viewport:

void ViewPort::setRounding (int xPixelsToRoundTo, int yPixelsToRoundTo); // zero means no rounding

If x or y rounding is desired (i.e. non zero) then this could be applied in Viewport::setViewPosition(). I made this changed and it fixed my list problem. I just set the y rounding to ListBox::getRowHeight(). The Viewport on the ListBox was accessible through ListBox::getViewport().

This way, old behavior is preserved, and I can get my list to scroll by whole rows only. Plus, this fixes the scrollbar as well (since the thumb could move the list by fractional rows).

Another useful feature would be to set the step amount for the scroll wheel. Right now its just multiplying the scroll wheel delta by 14 * stepSize, but in my app I would like to make it so that a single scroll wheel movement (regardless of the magnitude of the movement increments received in the function Viewport::mouseWheelMove()) will allow me to scroll my list by (number of fully visible rows - 1). If Viewport had a function like this:

void Viewport::setScrollWheelAbsoluteDeltaSteps (int deltaStepX, int deltaStepY);

then I could override resized() in my ListBox derived class, and set the delta on the viewport to the number of fully visible rows - 1. This would not change existing behavior.


I would like to see a stepped Scrollbar in the viewport.


[quote=“otristan”]I would like to see a stepped Scrollbar in the viewport.

Yeah you’re right. I looked into it further and the vertical page size of the Viewport’s Scrollbar gets set to the Viewport height. This is less than ideal for my purposes. If a list has N fully visible rows, the vertical Scrollbar page size should be (N-1)*rowHeight. So if you page down, for example, the full visible row that was previously at the bottom, should now be at the top of the list. This reassures the user of their position within the list and provides a visual confirmation that no rows were skipped while someone is looking through list contents a page at a time.

So in order to get these ListBox behaviors, what we need is a set of routines that allow us to activate these features:

  • Always round the Viewport content component’s height to a multiple of the ListBox row height

  • Set the Viewport Scrollbar’s page size to the number of fully visible rows - 1

  • Change the behavior of the vertical scroll wheel in the Viewport to always move by one Scrollbar page up or down regardless of the magnitude of the wheel movement passed to Viewport::mouseWheelMove().

Now I didn’t address the issue of horizontal scrolling because it’s no big deal but always rounding the Viewport content component X coordinate for a TableListBox so that the first currently visible scrolled to column always starts at local X coordinate 0 would be pretty amazing (and I imagine quite difficult lol). But I figured I would mention it for completeness.

Can we fix this? It’s super annoying now that I have a few hundred items in my list…

+1, this would be a welcome addition.