Progress bar inside a button in Pygame

2019-07-31 08:36发布

The desired behavior is:

When user hold the mouse on the button, the dark gray progress bar appears and starts to get incremented at a constant pace. I want to be able to determine how long it will take for it to completely fill (like 2 seconds). If the mouse move out the button BEFORE the progress bar has reached 100%, the progress bar should go straight to 0%. If the bar reaches 100%, the program should print something in the terminal.

Here is the code:

import sys
import pygame 
import time
from pygame.locals import *
from os import path

pygame.init()

screen = pygame.display.set_mode((900, int(900 * (16 / 9))))

clock = pygame.time.Clock()

BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
WHITE = (255, 255, 255)
BACKGROUND_COLOR = (237, 225, 192)
LIGHT_GRAY = (60, 60, 60)
GRAY = (30, 30, 30)

class Button:

    def __init__(self, screen, x, y, w, h, button_color_active, button_color_inactive, text, font, size = 50, text_color = BLACK):
        self.screen = screen

        self.game_folder = path.dirname(__file__)
        self.font = path.join(self.game_folder, font + '.ttf')

        self.x, self.y, self.w, self.h = x, y, w, h
        self.button_color_active = button_color_active
        self.button_color_inactive = button_color_inactive

        self.text, self.size = text, size
        self.text_color = text_color

        self.button_rect = pygame.Rect(self.x, self.y, self.w, self.h)
        self.button_font = pygame.font.Font(self.font, self.size)
        self.label = self.button_font.render(self.text, 1, self.text_color)

    def draw(self):
        if self.button_rect.collidepoint(pygame.mouse.get_pos()):
            #pygame.draw.rect(self.screen, self.button_color_inactive, self.button_rect)
            for progress in range(42):
                pygame.draw.rect(screen, LIGHT_GRAY, pygame.Rect(50,600,10*progress,80))
                pygame.display.update()

        else:
            pygame.draw.rect(self.screen, self.button_color_active, self.button_rect)
        self.screen.blit(self.label, (self.x + 20, self.y + 5))

    def is_clicked(self, mouse_pos):
        return bool(self.button_rect.collidepoint(mouse_pos))

    def set_new_color(self, active_color, inactive_color):
        self.button_color_active = active_color
        self.button_color_inactive = inactive_color

button_start = Button(screen, 50, 600, 400, 80, GRAY, LIGHT_GRAY, 'START', 'roboto-black', 50, WHITE)
while True:
    screen.fill(BACKGROUND_COLOR)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
    #pygame.draw.rect(screen, GRAY, pygame.Rect(50,600,400,80))
    #pygame.draw.rect(screen, LIGHT_GRAY, pygame.Rect(50,600,10*progress,80))
    button_start.draw()
    pygame.display.flip()
    clock.tick(60)
a = str(input('shomething: '))

1条回答
Ridiculous、
2楼-- · 2019-07-31 09:09

First you need a timer. You can use the dt (delta time) that pygame.clock.tick(fps) returns to increase a time variable. Do this only if the mouse is hovering over the button, otherwise reset the timer.

To calculate the width of the rect you can do this (proportionality):

width = time * coefficient

Here's a minimal example:

import pygame as pg


pg.init()

screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
FONT = pg.font.Font(None, 36)
BACKGROUND_COLOR = (237, 225, 192)
LIGHT_GRAY = (120, 120, 120)
GRAY = (30, 30, 30)

# Button variables.
button_rect = pg.Rect(50, 100, 200, 80)
max_width = 200  # Maximum width of the rect.
max_time = 4  # Time after which the button should be filled.
# Coefficient to calculate the width of the rect for a given time.
coefficient = max_width / max_time
time = 0

dt = 0
done = False

while not done:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            done = True

    mouse_pos = pg.mouse.get_pos()
    if button_rect.collidepoint(mouse_pos):
        # If mouse is over the button, increase the timer.
        if time < max_time:  # Stop increasing if max_time is reached.
            time += dt
            if time >= max_time:
                time = max_time
    else:  # If not colliding, reset the time.
        time = 0

    width = time * coefficient

    screen.fill(BACKGROUND_COLOR)
    pg.draw.rect(screen, LIGHT_GRAY, (51, 100, width, 80))
    pg.draw.rect(screen, GRAY, button_rect, 2)
    txt = FONT.render(str(round(time, 2)), True, GRAY)
    screen.blit(txt, (20, 20))

    pg.display.flip()
    dt = clock.tick(60) / 1000

pg.quit()
查看更多
登录 后发表回答