Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making a scrollbar but its inconsistent

Tags:

python

pygame

So I was just messing around trying to make a simple scroll bar. Basically, there are some buttons and a scroll bar. All I am trying to do is move the buttons up if scroll bar is moved down and move buttons down if scroll bar is moved up. Here is the code.

import pygame
import time

pygame.init()

window = pygame.display.set_mode((1200, 600))
font = pygame.font.Font(pygame.font.get_default_font(), 30)

ys = [] ##stores y-positions for the buttons
for y in range(25):
    ys.append((y * 101) + 100)

bar = pygame.Rect(550, 100, 10, (1 / len(ys) if len(ys) > 0 else 1) * 500)

scrollStart = False
updateButtons_Y = False

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()

    mousePressed = pygame.mouse.get_pressed()[0]
    mousePos = pygame.mouse.get_pos()
            
    window.fill((255, 255, 255))

    if (bar.y < 100): bar.y = 100
    if (bar.y + bar.height) > 500: bar.y = 500 - bar.height    
    pygame.draw.rect(window, (0, 0, 0), bar)

    if mousePressed and bar.collidepoint(mousePos) and not scrollStart:
        scrollStart = True
        scrollPosY = mousePos[1]
        
    if scrollStart:
        pygame.draw.rect(window, (255, 0, 0), bar)
        bar.y += mousePos[1] - scrollPosY
        if bar.y > 100  and bar.y + bar.height < 500:   
            for i in range(len(ys)):
                ys[i] -= (mousePos[1] - scrollPosY) * len(ys) * 0.3
        scrollPosY = mousePos[1]

    if not mousePressed and scrollStart:
        scrollStart = False        

    for i, y in enumerate(ys):
        pygame.draw.rect(window, (0, 0, 0), (10, y, 500, 100), 3)
        surf = font.render(f'{i}', True, (0, 0, 0))
        window.blit(surf, (100, y + 40))
        
    pygame.display.flip()

The problem I am having is that while scrolling up and down, they gradually get misplaced. For example, here is how it starts. Notice how the bar on the left and the buttons start on the same level. enter image description here

And here is how it ends up after scrolling up and down a few times.

enter image description here

I figured that this was the problem:

if scrollStart:
        pygame.draw.rect(window, (255, 0, 0), bar)
        bar.y += mousePos[1] - scrollPosY
        if bar.y > 100  and bar.y + bar.height < 500:   
            for i in range(len(ys)):
                ys[i] -= (mousePos[1] - scrollPosY) * len(ys) * 0.3
        scrollPosY = mousePos[1]

mousePos[1] - scrollPosY changes based on how fast the mouse is moved, so the amount by which is changes each frame was inconsistent. To fix that I replaced that with

if scrollStart:
        pygame.draw.rect(window, (255, 0, 0), bar)
        if mousePos[1] - scrollPosY != 0:
            speed = 1
            direction = math.copysign(speed, mousePos[1] - scrollPosY)
            bar.y += direction 
            if bar.y > 100  and bar.y + bar.height < 500:
                for i in range(len(ys)):
                    ys[i] -= direction   
        scrollPosY = mousePos[1]

This fixed that problem, but now the movement does not feel natural (either the scroll bar is moving way to slow or the buttons are moving way to fast).

So my question is: Is there a way for them to be consistent while also moving at different speeds?


1 Answers

Do not shift the position of the list elements, but compute the new position:

ys[i] -= offset

ys[i] = position

Compute the relative position of the bar:

scroll_height = (500 - 100) - bar.height 
scroll_rel = (bar.y - 100) / scroll_height

Compute the offset for the list elements:

box_height = (500 - 100)
list_height = 25 * 101
offset = (list_height - box_height) * scroll_rel

Set the new position of the elements:

for i in range(len(ys)):
    ys[i] = (i * 101) + 100 - offset

Changes:

while True:
   # [...]

   if scrollStart:

        bar.y = max(100, min(500 - bar.height, mousePos[1]))
        pygame.draw.rect(window, (255, 0, 0), bar)
        
        scroll_height = (500 - 100) - bar.height 
        scroll_rel = (bar.y - 100) / scroll_height
       
        box_height = (500 - 100)
        list_height = 25 * 101
        offset = (list_height - box_height) * scroll_rel
        
        for i in range(len(ys)):
            ys[i] = (i * 101) + 100 - offset

    # [...]
like image 99
Rabbid76 Avatar answered Nov 07 '25 09:11

Rabbid76



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!