I am trying create multiple buttons with each button consists of 2 rectangles in Pygame. However, the program would stuck for a second in a certain step probably due to a nested loop. Specifically, the "while loop" marked by the code fence in the main loop only works correctly only when being executed for the first time. If it is executed after the first time, the program would stop responding for a second. Is there anyway to correct that? I am currently testing it on on window 10 64 bit , Python 3.7.4, PyGame 1.9.6.
import pygame
import time
import random
pygame.init()
# Screen for displaying everything
display_width = 1200
display_height = 700
game_display = pygame.display.set_mode((display_width,display_height),pygame.RESIZABLE)
pygame.display.set_caption('Currently testing')
# Color for later use
red = (200,0,0)
green = (0,200,0)
bright_red = (255,0,0)
bright_green = (0,255,0)
black= (0,0,0)
white= (225,225,225)
grey = (166,166,166)
font_color= black
background_color= white
def create_button(x,y,w,h,name,callback):
# lower part of the button
button_upper= pygame.Rect(x, y, w, h)
# upper part of the button
button_lower= pygame.Rect(x, y+ h, w, h)
# define the area of the button for later interaction
interactable= pygame.Rect(x, y, w, 2*h)
button_info= {'button_lower':button_lower,
'button_upper':button_upper,
'button_name':name,
'interaction':interactable,
'button function':callback,
'color_upper':red, 'color_lower':green}
return button_info
def draw_button(button_info):
# Drawing lower part of the button
pygame.draw.rect(game_display,
button_info['color_lower'],
button_info['button_lower'])
# Drawing upper part
pygame.draw.rect(game_display,
button_info['color_upper'],
button_info['button_upper'])
# Text object for later use
def text_object(text,font):
textSurface= font.render(text,True,font_color)
return textSurface, textSurface.get_rect()
def central_text(text,size,pos):
largeText = pygame.font.Font('freesansbold.ttf',size)
textSurface, textRect = text_object(text,largeText)
textRect.center = (pos)
game_display.blit(textSurface,textRect)
def main():
# The function of the button, temporarily
def print_name():
nonlocal button
nonlocal done
game_display.fill(background_color)
central_text('Button'+' '+button['button_name']+' '+'clicked',80,(display_width/2,display_height/2))
pygame.display.update()
time.sleep(3)
done= True
# function of non-interactable block
def do_nothing():
pass
# Actually create those button
button_1= create_button(display_width*0.3,display_height*0.5,40,40,'1',print_name)
button_2= create_button(display_width*0.35,display_height*0.5,50,50,'2',print_name)
button_3= create_button(display_width*0.4,display_height*0.5,30,30,'3',print_name)
button_4= create_button(display_width*0.45,display_height*0.5,20,20,'4',print_name)
button_5= create_button(display_width*0.5,display_height*0.5,40,30,'5',print_name)
button_6= create_button(display_width*0.55,display_height*0.5,50,40,'6',print_name)
button_7= create_button(display_width*0.6,display_height*0.5,50,30,'7',print_name)
button_8= create_button(display_width*0.65,display_height*0.5,50,50,'8',print_name)
button_9= create_button(display_width*0.7,display_height*0.5,30,40,'9',print_name)
button_10= create_button(display_width*0.75,display_height*0.5,60,70,'10',print_name)
# Create non-interactable rectangles
block_1= create_button(display_width*0.75,display_height*0.8,40,40,'10',do_nothing)
block_2= create_button(display_width*0.7,display_height*0.8,40,40,'9',do_nothing)
block_3= create_button(display_width*0.7,display_height*0.8,40,40,'8',do_nothing)
# Select and store those button in different list, with a non-interactable
# rectangles in each list
list_1=[button_1, button_2, button_3, button_4, button_5,
button_6, button_7, button_8, button_9, button_10]
list_2=[button_1, button_2, button_3, button_4, button_5,
button_6, button_7, block_3, button_9, button_10]
list_3=[button_1, button_2, button_3, button_4, button_5,
button_6, button_7, button_8, block_2, button_10]
list_4=[button_1, button_2, button_3, button_4, button_5,
button_6, button_7, button_8, button_9, block_1]
# Attempt to control how many times and in what sequence those
# button list would be used
index= [1,1,2,2,2,3,3,4,4]
random.shuffle(index)
text=' ' # a text that would accompany all the buttons
for i in range (len(index)):
done = False
if index[i] == 1:
button_list= list_1
text= 'text 1'
elif index[i] == 2:
button_list= list_2
text= 'text 2'
elif index[i] == 3:
button_list= list_3
text= 'text 3'
else:
button_list= list_4
text= 'text 4'
# display message 1
game_display.fill(background_color)
central_text('test_text 1',80,(display_width/2,display_height/2))
pygame.display.update()
time.sleep(2)
# display message 2
game_display.fill(background_color)
central_text('test_text 2',80,(display_width/2,display_height/2))
pygame.display.update()
time.sleep(3)
'''This is where the program would stuck for a second'''
game_display.fill(background_color)
central_text(text,30,(display_width/2,display_height*0.2))
while not done:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.display.quit()
pygame.quit()
quit()
# block that would be executed when left mouse button is pressed
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
for button in button_list:
if button['interaction'].collidepoint(event.pos):
button['button function']()
elif event.type == pygame.MOUSEMOTION:
# When the mouse gets moved, change the color of the
# buttons if they collide with the mouse.
for button in button_list:
if not button['button function']== do_nothing:
if button['interaction'].collidepoint(event.pos):
button['color_upper']= red
button['color_lower']= green
else:
button['color_upper']= bright_red
button['color_lower']= bright_green
for button in button_list:
# Turn non-interactable blocks into grey
if button['button function']== do_nothing:
button['color_upper']= grey
button['color_lower']= grey
draw_button(button)
pygame.display.update()
'''the block above would some times stucks the program'''
main()