Как привязать колёсико мыши к полосе прокрутки в pygame
Я написал класс полосы прокрутки, в котором я хочу привязать колесо мыши к полосе прокрутки, но всё безуспешно. Я попробовал задавать новое положение элементов(кнопок) и координаты самого ползунка, исходя от текущей Y координаты последнего элемента, но у меня выходит так, что ползунок идёт то очень быстро, то очень медленно. Так вот, я хочу чтобы, когда я прокручиваю элементы(кнопки) при помощи колёсика мыши, вместе с ним также двигался ползунок с элементами.
p.s. Я смотрел как это реализовано в pygame_menu и tkinter, но ничего так и не понял
Вот сам класс(он ещё толком не дописан, поскольку я наткнулся на эту проблему):
class ScrollBar:
VERTICAL = "Y"
HORIZONTAL = "X"
def __init__(self, screen, buttons: Button, direction, x=0, y=0, width=100, height=100, color=(105, 105, 105),
slider_color=(50, 50, 50)):
self.screen = screen
self.buttons = buttons
self.direction = direction
self.BAR_X = x
self.BAR_Y = y
self.BAR_WIDTH = 20
self.BAR_HEIGHT = height
self.width = width
self.height = height
self.color = color
self.slider_color = slider_color
self.SLIDER_WIDTH = 20
self.SLIDER_HEIGHT = 20
self.bar_rect = pygame.Rect(self.BAR_X, self.BAR_Y, self.BAR_WIDTH, self.BAR_HEIGHT)
self.SLIDER = pygame.Rect(self.BAR_X, self.BAR_Y, self.SLIDER_WIDTH, self.SLIDER_HEIGHT)
#метод входа в класс
def pack(self):
self.draw_bar()
if not self.buttons is None and len(self.buttons) > 0 and self.buttons != []:
for button in self.buttons:
if button.y + button.height >= self.BAR_Y and button.y <= self.BAR_Y + self.height:
button.draw(self.screen)
if pygame.Rect(self.BAR_X, self.BAR_Y, self.BAR_WIDTH + self.buttons[0].width, self.height).collidepoint(*pygame.mouse.get_pos()):
self.scroll_mouse_wheel()
self.scroll_bar()
def draw_bar(self):
pygame.draw.rect(self.screen, self.color, self.bar_rect)
pygame.draw.rect(self.screen, self.slider_color, self.SLIDER)
#сам скроллбар
def scroll_bar(self):
MOUSE_CLICK = pygame.mouse.get_pressed()
self.SLIDER_HEIGHT = (1 / len(self.buttons) if len(self.buttons) > 0 else 1) * (self.BAR_Y + self.height)
if self.SLIDER_HEIGHT < 20:
self.SLIDER_HEIGHT = 20
self.SLIDER.height = self.SLIDER_HEIGHT
if self.cursor_in_scrollbar():
if MOUSE_CLICK[0] == 1:
self.SLIDER.y = self.get_slider_y()
speed_y = self.get_slider_speed_y()
for i in range(len(self.buttons)):
self.buttons[i].y = (i * self.buttons[-1].height) + self.BAR_Y - speed_y
def add_buttons(self, buttons: Button):
self.buttons.extend(buttons)
def get_buttons(self):
return self.buttons
#прокрутка элементов при помощи колёсика мыши
def scroll_mouse_wheel(self):
for event in pygame.event.get():
if (event.type == pygame.MOUSEBUTTONDOWN and event.button == 4) or (
event.type == pygame.KEYDOWN and event.key == pygame.K_UP):
self.move_buttons_up()
#устанавливаю новое значение координаты Y для ползунка
self.SLIDER.y = self.get_slider_y_for_mousewheel()
if (event.type == pygame.MOUSEBUTTONDOWN and event.button == 5) or (
event.type == pygame.KEYDOWN and event.key == pygame.K_DOWN):
self.move_buttons_down()
#устанавливаю новое значение координаты Y для ползунка
self.SLIDER.y = self.get_slider_y_for_mousewheel()
def move_buttons_up(self):
for index, button in enumerate(self.buttons):
button.y += button.height
if index <= self.BAR_Y < button.y:
for button1 in self.buttons:
button1.y -= button1.height
def move_buttons_down(self):
for index, button in enumerate(self.buttons):
button.y -= button.height
if index + 2 > len(self.buttons) and button.y + button.height < self.height:
for button1 in self.buttons:
button1.y += button1.height
#получаю новую Y координату для ползунка, если прокручивать при помощи мыши
def get_slider_y(self):
return max(self.BAR_Y, min(self.BAR_Y + self.height - self.SLIDER.height, pygame.mouse.get_pos()[1]))
#вот тут и находиться сама проблема, я не понимаю как рассчитать новую Y координату для ползунка
#мне толком не понятно, что взять для расчётов новой Y координаты для ползунка. Это или Y координата
#первого или последнего элемента(кнопки), или вообще что-то другое
def get_slider_y_for_mousewheel(self):
button = self.buttons[-1]
return max(self.BAR_Y, min(self.BAR_Y + self.height - self.SLIDER.height, (self.BAR_Y + self.height) - (button.y + button.height) / len(self.buttons)))
#получение новой координаты для текущего элемента
def get_slider_speed_y(self):
try:
scroll_height = self.height - self.SLIDER.height
scroll_rel = (self.SLIDER.y - self.BAR_Y) / scroll_height
offset = (len(self.buttons) * self.buttons[-1].height - self.height) * scroll_rel
except ZeroDivisionError:
offset = 0
return offset
def cursor_in_scrollbar(self):
return self.bar_rect.collidepoint(*pygame.mouse.get_pos())
Правка 1:
def get_slider_y_for_mousewheel(self):
button = self.buttons[-1]
elements_on_screen = (self.BAR_Y + self.height) / button.height
speed_y = (self.BAR_Y + self.height) - (button.y + button.height) * elements_on_screen / len(self.buttons)
return max(self.BAR_Y, min(self.BAR_Y + self.height - self.SLIDER.height, speed_y))
Я чувствую что я на правильном пути, но всё же что-то не так. Элементы прокручиваются нормально вместе со скроллбаром, но он слегка не доходит до своей границы. Подскажите пожалуйста чему должно быть равно speed_y для корректной работы?
Ответы (1 шт):
Ваш вопрос дублировался в английской версии и был решен, посмотрите тут