Не работает код обработки нажатия на кнопку в Pygame

Люди, такая проблема. Делал свой класс кнопки на Pygame, и заметил, что при быстром нажатии на разные кнопки код не обрабатывает нажатия (не выводит в консоль текст).

main.py:

import sys
import pygame


class Button:
    def __init__(self, x, y, w, h, text):
        self.rect = pygame.Rect(x, y, w, h)
        self.text = text
        self.state = "normal"
        self.font = pygame.font.Font(None, 24)
        
    def draw(self, surface):
        color = {"normal": (200,200,200), "hover": (150,150,150), "clicked": (100,100,100)}[self.state]
        pygame.draw.rect(surface, color, self.rect)
        text = self.font.render(self.text, True, (0,0,0))
        surface.blit(text, text.get_rect(center=self.rect.center))
    
    def handle_event(self, event):
        mouse_pos = pygame.mouse.get_pos()
        
        if event.type == pygame.MOUSEMOTION:
            self.state = "hover" if self.rect.collidepoint(mouse_pos) else "normal"
            
        elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
            if self.rect.collidepoint(mouse_pos):
                self.state = "clicked"
                
        elif event.type == pygame.MOUSEBUTTONUP and event.button == 1:
            if self.rect.collidepoint(mouse_pos) and self.state == "clicked":
                print(f"Clicked {self.text}")  # не выводится при быстром нажатии на разные кнопки 
                return True
            self.state = "normal"
        return False

# Test setup
pygame.init()
screen = pygame.display.set_mode((400, 300))
buttons = [Button(100,50+i*70,200,50,f"Button {i+1}") for i in range(3)]
clock = pygame.time.Clock()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT: pygame.quit(); sys.exit()
        for btn in buttons: btn.handle_event(event)
    
    screen.fill((240,240,240))
    for btn in buttons: btn.draw(screen)
    pygame.display.flip()
    clock.tick(60)

Ответы (1 шт):

Автор решения: S. Nick

Я заменил только

    self.state == "clicked"

на

    (self.state == "clicked" or self.state == "hover")

стало лучше.

Я self.counter для наглядности тестирования.

Проверьте, но мне кажется, что это еще не все изменения, которые вам надо будет сделать. Возможно вам придется менять логику вашего приложения.

main.py

import sys
import pygame


class Button:
    def __init__(self, x, y, w, h, text):
        self.rect = pygame.Rect(x, y, w, h)
        self.text = text
        self.state = "normal"
        self.font = pygame.font.Font(None, 24)
        self.counter = 0                              # +++ для теста
        
    def draw(self, surface):
        color = {
            "normal": (200, 200, 200), 
            "hover": (150, 150, 220), 
            "clicked": (200, 100, 100)
        }[self.state]
        pygame.draw.rect(surface, color, self.rect)
        text = self.font.render(
            f'{self.text}-=-{self.counter}', True, (0, 0, 0))
        surface.blit(text, text.get_rect(center=self.rect.center))
    
    def handle_event(self, event):
        mouse_pos = pygame.mouse.get_pos()
       
        if event.type == pygame.MOUSEMOTION:
            self.state = "hover" if self.rect.collidepoint(mouse_pos) \
                                else "normal"
        elif event.type == pygame.MOUSEBUTTONDOWN and event.button==1:
            if self.rect.collidepoint(mouse_pos):
                self.state = "clicked"
                self.counter += 1
                
        elif event.type == pygame.MOUSEBUTTONUP and event.button==1:
            if self.rect.collidepoint(mouse_pos) and \
                (self.state == "clicked" or self.state == "hover"):
# !!! +++                                ^^^^^^^^^^^^^^^^^^^^^^^^   
#                self.state == "clicked":

                print(f"Clicked {self.text} {' '*10*int(self.text[-1])}{self.counter}")  # не выводится при быстром нажатии на разные кнопки 
                return True
            self.state = "normal"
        return False

# Test setup
pygame.init()
screen = pygame.display.set_mode((400, 300))
buttons = [Button(100, 50+i*70, 200, 50, f"Button {i+1}") \
    for i in range(3)]
clock = pygame.time.Clock()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT: 
            pygame.quit(); 
            sys.exit()
        for btn in buttons: 
            btn.handle_event(event)
    
    screen.fill((240, 240, 240))
    for btn in buttons: btn.draw(screen)
    pygame.display.flip()
    clock.tick(60)

введите сюда описание изображения

→ Ссылка