• Rapidbly updating scrollbar size

    From Joe Betz@21:1/5 to All on Tue Feb 22 12:15:58 2022
    What is the correct way to ensure that a scrollbar is updated when the content it manages changes size at a fast rate?

    I'm using a GdiplusDoubleBufferedView inside of a ScrollingDecorator to render a list of 100+ items. Whenever a new item gets added, I call `self invalidate` to rerender the list. However, the scrollbar doesn't seem to be getting updated accordingly. The
    only thing that seems to work is adding a call to `creationParent layout`, but that results in the list flickering with each item added.

    I see a couple solutions:
    - set up a debouncer to ensure that layout isn't recalculated with every item added, e.g., only after 100ms have passed since last item added
    - batch up items upstream to reduce layout recalculation

    But neither seem ideal.

    Are there any better ways to handle this situation?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Zenchess@21:1/5 to All on Tue Feb 22 20:13:43 2022
    I don't know how your situation works, but I was using 'self invalidate' to update my chessboard program, and what I had to eventually do was only redraw the nearby squares instead of the entire repaint. Don't know if that can help you but I thought I'd
    just throw that out there

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Joe Betz@21:1/5 to All on Thu Feb 24 19:00:46 2022
    Okay, think I figured it out. Calling `creationParent layout` was doing way more work than necessary, so I extracted the logic for updating the scrollbar into a separate function and am now only calling that instead.

    VirtualScrollingDecorator>>updateScrollbar
    | layoutContext newScroll scrolled clientExtent desiredExtent viewExtent |
    layoutContext := LayoutContext forContainer: self.
    scrolled := self firstSubView.
    clientExtent := layoutContext clientExtentOf: self.
    desiredExtent := scrolled layoutExtent: layoutContext.
    viewExtent := clientExtent max: desiredExtent.
    newScroll := ((scrollOffset x min: viewExtent x - clientExtent x) max: 0)
    @ ((scrollOffset y min: viewExtent y - clientExtent y) max: 0).
    layoutContext setView: scrolled rectangle: (scrollOffset negated extent: viewExtent).
    self scrollOffset: newScroll context: layoutContext.
    self updateScrollBars: layoutContext

    There was still a case of the content flickering whenever I scrolled to a newly added item to the list (as opposed to immediately when it's added), but I was able to find a similar solution there by overriding the `wmPaint:wParam:lParam` method to skip
    the call to `self ensureLayoutValid`. I think this is okay since the layout of everything inside the GDI+ canvas is handled by my custom list widget class.

    I don't know how your situation works, but I was using 'self invalidate' to update my chessboard program, and what I had to eventually do was only redraw the nearby squares instead of the entire repaint. Don't know if that can help you but I thought I'
    d just throw that out there

    Were you using GdiplusDoubleBufferedView or was the chessboard created with MVP components?

    I don't think there is a way to redraw subregions of a GDI+ canvas, nor would it be desirable since it already implements double buffering.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)