# Scrollbar problems on Windows

**URL:** <https://racket.discourse.group/t/scrollbar-problems-on-windows/3314>\
**Category:** Questions & Answers\
**Created:** [November 13, 2024, 4:12pm UTC](https://racket.discourse.group/t/scrollbar-problems-on-windows/3314 "2024-11-13T16:12:12Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![jjsimpso](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/jjsimpso/32/602_2.png) [@jjsimpso](https://racket.discourse.group/u/jjsimpso)\
**Post date:** [November 13, 2024, 4:12pm UTC](https://racket.discourse.group/t/scrollbar-problems-on-windows/3314/1 "2024-11-13T16:12:12Z")

</div>

In my GUI application, I have a number of scrollbar-related problems in Windows that I don't see on Linux. My app has a custom `canvas%` with manual scrollbars.

The main problem occurs when scrolling a very large virtual canvas (\> 30,000 pixels high or so). Scrolling via dragging the scroll thumb(?) seems to work as expected until I release the left mouse button. At that point I see an `on-scroll` event with a bogus position in the `event` argument. It kinda seems like an integer overflow issue at around 32,768 but it isn't super consistent. Scrolling via `set-scroll-pos` works fine even with very large values.

I can easily have a virtual canvas with dimensions \> 500,000 pixels, so this is a problem.

On a more general note, I've implemented scrolling using units of pixels. Is that how manual scrollbars were intended to be used? I suppose I could use a larger unit, but with the sizes I deal with I expect I will still run into this issue if I keep any degree of fine-grained scrolling.

Note: it looks like the 32,000 limit is a known issue. See this commit:  
[https://github.com/racket/gui/commit/4ad479277821641fb39b8ae8e9c20a76b36e9e9a](https://github.com/racket/gui/commit/4ad479277821641fb39b8ae8e9c20a76b36e9e9a)

Also, see an issue I previously opened concerning the limit to `set-scroll-range`:  
[https://github.com/racket/gui/issues/295](https://github.com/racket/gui/issues/295)

Any thoughts or suggestions are appreciated!

---

<div class="post-metadata">

**Author:** ![jjsimpso](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/jjsimpso/32/602_2.png) [@jjsimpso](https://racket.discourse.group/u/jjsimpso)\
**Post date:** [November 14, 2024, 1:48am UTC](https://racket.discourse.group/t/scrollbar-problems-on-windows/3314/2 "2024-11-14T01:48:50Z")

</div>

Right now I'm leaning toward increasing the "scroll unit" when the scroll range approaches 32,000. That way I can retain fine grained scrolling for smaller canvases.

Hopefully that doesn't lead to any of the other problems I've seen on Windows. Namely that I've had trouble when dynamically changing `set-scroll-page`. It sometimes causes the scrollbar to appear (albeit in an inactive state) even though it should be hidden by `show-scrollbars`. Similar things would also happen when setting the scroll range to 0 on Windows.

---

<div class="post-metadata">

**Author:** ![jjsimpso](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/jjsimpso/32/602_2.png) [@jjsimpso](https://racket.discourse.group/u/jjsimpso)\
**Post date:** [November 18, 2024, 3:28pm UTC](https://racket.discourse.group/t/scrollbar-problems-on-windows/3314/3 "2024-11-18T15:28:22Z")

</div>

Here's what I did to avoid the scroll range limit:

```scheme
(define hscroll-enabled? #f)
(define vscroll-enabled? #f)

(define/override (get-scroll-pos which)
  (cond
    [(eq? which 'vertical)
     (* (super get-scroll-pos which) scrollbar-vert-step-size)]
    [else
     (super get-scroll-pos which)]))
 
(define/override (get-scroll-range which)
  (cond
    [(eq? which 'vertical)
     (* (super get-scroll-range which) scrollbar-vert-step-size)]
    [else
     (super get-scroll-range which)]))
 
(define/override (set-scroll-pos which value)
  (cond
    [(eq? which 'vertical)
     ;(printf " set-scroll-pos: ~a, ~a(~a)~n" which value (quotient value scrollbar-vert-step-size))
     (super set-scroll-pos which (quotient value scrollbar-vert-step-size))]
    [else
     (super set-scroll-pos which value)]))

(define/override (set-scroll-range which value)
  (cond
    [(eq? which 'vertical)
     ;(printf " set-scroll-range: ~a, ~a(~a)~n" which value (/ value scrollbar-vert-step-size))
     (super set-scroll-range which (quotient value scrollbar-vert-step-size))]
    [else
     (super set-scroll-range which value)]))

(define/override (set-scroll-page which value)
  (cond
    [(eq? which 'vertical)
     ;(printf " set-scroll-page: ~a, ~a(~a)~n" which value (/ value scrollbar-vert-step-size))
     (super set-scroll-page which (quotient value scrollbar-vert-step-size))]
    [else
     (super set-scroll-page which value)]))

;; update the manual scrollbars range and hide/unhide them
;; new width and height are in pixels
(define (update-scrollbars new-width new-height)
  #;(printf "update-scrollbars, thread=~a~n" (current-thread))
  (when (semaphore-try-wait? edit-lock)
    (define-values (dw dh) (get-drawable-size))
    (set-scroll-range 'horizontal (exact-truncate (max 1 (- new-width dw))))
    (set-scroll-range 'vertical (exact-truncate (max 1 (- new-height dh))))
    (set-scroll-page 'horizontal 100)
    (set-scroll-page 'vertical (max 1 dh))
    ;; when scrollbar's are enabled, we need to recreate the offscreen bitmap because the client size changes
    ;(printf "hscroll-enabled=~a, vscroll-enabled=~a~n" hscroll-enabled? vscroll-enabled?)
    (when (not (equal? hscroll-enabled? (> new-width dw)))
      (set! hscroll-enabled? (> new-width dw))
      ;(printf " hscroll enabled changed to ~a (nw=~a, dw=~a)~n" hscroll-enabled? new-width dw)
      (send offscreen-dc set-bitmap #f)
      (show-scrollbars hscroll-enabled? vscroll-enabled?))
    (when (not (equal? vscroll-enabled? (> new-height dh)))
      (set! vscroll-enabled? (> new-height dh))
      ;(printf " vscroll enabled changed to ~a (nh=~a, dh=~a)~n" vscroll-enabled? new-height dh)
      (send offscreen-dc set-bitmap #f)
      (show-scrollbars hscroll-enabled? vscroll-enabled?)
      ;; the vertial scrollbar changes the client width and thus the layout
      ;; so if it changes we need to rerun the layout
      (reset-layout)
      (define-values (vx vy) (get-virtual-size))
      (define-values (ndw ndh) (get-drawable-size))
      (set-scroll-range 'horizontal (exact-truncate (max 1 (- vx ndw))))
      (set-scroll-range 'vertical (exact-truncate (max 1 (- vy ndh))))
      (set-scroll-page 'vertical (max 1 ndh)))
    (semaphore-post edit-lock)))

```

Elsewhere in the class, I set `scrollbar-vert-step-size` after loading the canvas's contents:

```scheme
(if (< canvas-height 30000)
      (set! scrollbar-vert-step-size 1)
      (set! scrollbar-vert-step-size (ceiling (/ canvas-height 30000))))

```

This appears to work well. However, there are still issues(Windows only) with hidden scrollbars appearing, presumably due to calls to `set-croll-page` or `set-scroll-range` in my `update-scrollbars` function.

---

<div class="post-metadata">

**Author:** ![gneuner](https://avatars.discourse-cdn.com/v4/letter/g/b9e5f3/32.png) [@gneuner](https://racket.discourse.group/u/gneuner)\
**Post date:** [November 20, 2024, 8:54pm UTC](https://racket.discourse.group/t/scrollbar-problems-on-windows/3314/4 "2024-11-20T20:54:23Z")

</div>

Don't know about Linux, but Windows scrollbars do have a (small-ish) limit to their range. Best way to deal with it is to pick a useful scale, e.g., 100, 1000, etc., limit the scrollbar to that range, and then map it to your scrollable area.

---

<div class="post-metadata">

**Author:** ![jjsimpso](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/jjsimpso/32/602_2.png) [@jjsimpso](https://racket.discourse.group/u/jjsimpso)\
**Post date:** [November 21, 2024, 12:04am UTC](https://racket.discourse.group/t/scrollbar-problems-on-windows/3314/5 "2024-11-21T00:04:29Z")

</div>

Yes, that is what I finally settled on. I dynamically calculate the range so that I use as fine-grained a scrollbar step size as I can.

This is still useful on Linux in cases where the scrollbar range would exceed 1 million without any scaling. I haven't tried it in MacOS yet.
