How do I implement option buttons and change the button color in PyGame?
When you draw the button, you have to set the color dependent on the global variable clicked
:
def draw_button(self):
global clicked
# get mouse position
pos = pygame.mouse.get_pos()
# create pygame Rect object for the button
button_rect = Rect(self.x, self.y, self.width, self.height)
# check mouseover and clicked conditions
hover = button_rect.collidepoint(pos)
if hover and pygame.mouse.get_pressed()[0] == 1:
clicked = not clicked
color = self.button_col
if clicked:
color = self.click_col
elif hover:
color = self.hover_col
pygame.draw.rect(screen, color, button_rect)
Anyway, that won't satisfy you, because pygame.mouse.get_pressed()
returns a list of Boolean values that represent the state (True
or False
) of all mouse buttons. The state of a button is True
as long as a button is held down.
You have to use MOUSEBUTTONDOWN
event. The MOUSEBUTTONDOWN
event occurs once when you click the mouse button and the MOUSEBUTTONUP
event occurs once when the mouse button is released. The pygame.event.Event()
object has two attributes that provide information about the mouse event. pos
is a tuple that stores the position that was clicked. button
stores the button that was clicked.
If you have multiple buttons that you have to interact with each other, a single clicked
status is not enough. You need a separate "clicked" state for each button. If the clicked state of 1 button becomes True
, the states of the other keys must be set to False
. I recommend to implement a RadioButton
class for this.
See also Mouse and Sprite.
Minimal example:
repl.it/@Rabbid76/PyGame-RadioButton
import pygame
class RadioButton(pygame.sprite.Sprite):
def __init__(self, x, y, w, h, font, text):
super().__init__()
text_surf = font.render(text, True, (0, 0, 0))
self.button_image = pygame.Surface((w, h))
self.button_image.fill((96, 96, 96))
self.button_image.blit(text_surf, text_surf.get_rect(center = (w // 2, h // 2)))
self.hover_image = pygame.Surface((w, h))
self.hover_image.fill((96, 96, 96))
self.hover_image.blit(text_surf, text_surf.get_rect(center = (w // 2, h // 2)))
pygame.draw.rect(self.hover_image, (96, 196, 96), self.hover_image.get_rect(), 3)
self.clicked_image = pygame.Surface((w, h))
self.clicked_image.fill((96, 196, 96))
self.clicked_image.blit(text_surf, text_surf.get_rect(center = (w // 2, h // 2)))
self.image = self.button_image
self.rect = pygame.Rect(x, y, w, h)
self.clicked = False
self.buttons = None
def setRadioButtons(self, buttons):
self.buttons = buttons
def update(self, event_list):
hover = self.rect.collidepoint(pygame.mouse.get_pos())
for event in event_list:
if event.type == pygame.MOUSEBUTTONDOWN:
if hover and event.button == 1:
for rb in self.buttons:
rb.clicked = False
self.clicked = True
self.image = self.button_image
if self.clicked:
self.image = self.clicked_image
elif hover:
self.image = self.hover_image
pygame.init()
window = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
font50 = pygame.font.SysFont(None, 50)
radioButtons = [
RadioButton(50, 40, 200, 60, font50, "option 1"),
RadioButton(50, 120, 200, 60, font50, "option 2"),
RadioButton(50, 200, 200, 60, font50, "option 3")
]
for rb in radioButtons:
rb.setRadioButtons(radioButtons)
radioButtons[0].clicked = True
group = pygame.sprite.Group(radioButtons)
run = True
while run:
clock.tick(60)
event_list = pygame.event.get()
for event in event_list:
if event.type == pygame.QUIT:
run = False
group.update(event_list)
window.fill(0)
group.draw(window)
pygame.display.flip()
pygame.quit()
exit()
How do I change the color of a button once it is clicked in Pygame?
global clickedButtons,sumOfCosts,textDisp
clickedButtons=[]
sumOfCosts=[0,0]
textDisp = None
def addCostsAndDisplay(msg,cost,weight):
global sumOfCosts
sumOfCosts[0]+=cost
sumOfCosts[1]+=weight
basicfont = pygame.font.SysFont(None, 48)
text = basicfont.render('adding '+str(msg)+' adds up to '+str(sumOfCosts[0])+' and weighs '+str(sumOfCosts[1]), True, (255, 0, 0), (255, 255, 255))
return text
def button2(msg,x,y,w,h,ic,ac,cost=1,weight=1, action=None):
global clickedButtons,textDisp
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x+w > mouse[0] > x and y+h > mouse[1] > y:
pygame.draw.rect(gameDisplay, ac, (x,y,w,h))
if click[0] == 1 and action != None:
if not (msg in clickedButtons):
#Save that this button has been clicked
clickedButtons.append(msg)
textDisp=addCostsAndDisplay(msg,cost,weight)
if action == "START":
game_loop()
elif action == "BACK":
game_intro()
quit()
elif action == "Playstation 4":
print("")
else:
#Check if this button has been clicked
if (msg in clickedButtons):
pygame.draw.rect(gameDisplay, ac, (x,y,w,h))
else:
pygame.draw.rect(gameDisplay, ic, (x,y,w,h))
smallText = pygame.font.Font("freesansbold.ttf", 20)
textSurf, textRect = text_objects(msg, smallText)
textRect.center = ( (x+(w/2)), (y+(h/2)) )
gameDisplay.blit(textSurf, textRect)
#Selection Screen
def game_select_items_menu():
global textDisp
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
gameSelectItems = False
while not gameSelectItems:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
blank_image(x, y)
if (not textDisp is None):
screen=pygame.display.get_surface()
textRect=textDisp.get_rect()
textRect.centerx = x
textRect.centery = y
screen.blit(textDisp,textRect)
button2("Xbox One", 374, 60, 168, 48, white, orange,10,20,"Xbox One") #XBOX ONE - BUTTON (TOP ROW)
button2("Playstation 4", 200, 60, 168, 48, white, orange,20,20"Playstation 4")#PLAYSTATION 4 - BUTTON (TOP ROW)
button("Kettle", 30, 60, 163, 48, white, orange)#Kettle - BUTTON (TOP ROW)
button("Lewi Jeans", 374, 160, 168, 48, white, orange)#LEWI JEANS - BUTTON(SECOND ROW)
button("MacBook", 200, 160, 168, 48, white, orange)#MACBOOK - BUTTON (SECOND ROW)
button("Samsung TV", 30, 160, 163, 48, white, orange)#SAMSUNG TV - BUTTON (SECOND ROW)
button("Nike Air Max", 374, 250, 168, 48, white, orange)#NIKE AIR MAX - BUTTON (THIRD ROW)
button("Tablet", 200, 250, 168, 48, white, orange)#TABLET - BUTTON (THIRD ROW)
button("Perfume", 30, 250, 163, 48, white, orange)#PERFUME - BUTTON (THIRD ROW)
#button("", 30, 340, 300, 150, white, orange)#Print Box
#Bottom buttons(Start,Back)
button2("START", 374, 370, 163, 48,green, green_bright,0,0 "START")#START - BUTTON (BOTTOM)
button2("BACK", 374, 430, 163, 48, green, green_bright,0,0 "BACK")#BACK - BUTTON (BOTTOM)
pygame.display.update()
clock.tick(80) #Setting the fps
Change these lines to change the coordinates of the text (They are close to the end)
textRect.centerx = x
textRect.centery = y
Try it out.
Changing background color to buttons generated in a for loop
If someone is searching for the same thing the problem was that the buttons could configure because they weren't even saved anywhere. My solution was to create a separate function to create buttons with a return statement to initially save the buttons and then using tuples call those buttons to configure them.
def __init__(self):
super().__init__()
self.button = {}
self.turn = 'X'
for i in range(3):
for j in range(3):
self.button[(i,j)]=self.create_button(i, j)
def create_button(self, x, y):
self.button1 = Button(root, width=10, height=5, bg='#E0E0E0', fg='#6D6D6D', command=lambda i=x, j=y: self.pressed_button(i, j),)
self.button1.grid(row=x, column=y)
return self.button1
def pressed_button(self, i, j):
label = Label(root, text=self.turn, fg='#E0E0E0', bg='#6D6D6D')
label.grid(row=i, column=j)
self.button[(i, j)].configure(bg='#6D6D6D')
My buttons in Pygame are not changing colors due to overlapping
Thought gamestate parameters were the hangup; so I put those in a dictionary, to print them all out during clicks. It'll be good for debugging. Turned out to be if
/ elif
chain, but I don't need credit for that.
Would like to mention that ya don't need to initialize objects more than once in your various modules though; can run into circular imports with overlapping values. Might think something's one way and it ends up being another.
Game1.py
#! /usr/bin/env python3
from pygame_init import *
from Game2 import *
## Module for game logic
def keep_waiting_3():
our_game_display .fill(black)
text('Nothing still...wait! You hear something!', 0, halfheight -100)
win .blit(our_game_display, origin)
pygame .display .update()
def keep_waiting_2():
our_game_display.fill(black)
text('Are you sure you want to keep waiting?', 0, halfheight -100)
text("Maybe this isn't worth it...You could always choose the other options.", 0, halfheight -50)
win .blit(our_game_display, origin)
Wait3Button .draw( win, white)
SearchButton .draw(win, white)
YellHelpButton .draw(win, white)
pygame.display .update()
def keep_waiting():
our_game_display .fill( black )
text( 'You continue to sit and wait. Will anything happen?', 0, halfheight -100 )
text( 'You can keep waiting..or choose the other options.', 0, halfheight -50 )
win .blit( our_game_display, origin )
Wait2Button .draw( win, white)
SearchButton .draw(win, white)
YellHelpButton .draw(win, white)
pygame .display .update()
def yell_choice_2():
our_game_display .fill( black )
text( "Despite the warning, you yell 'Hello? Who's there?'", 0, halfheight -100 )
win .blit( our_game_display, origin )
pygame .display .update()
def yell_choice():
our_game_display .fill( black )
text( "You yell 'Hello?', out into the darkness.", 0, halfheight -100 )
text( "Immediately you hear someone whisper back 'Be quiet!'.", 0, halfheight -50 )
win .blit( our_game_display, origin )
Yell2Button .draw( win, white)
pygame .display .update()
def sit_choice():
our_game_display .fill( black )
text( 'So you decided to sit and wait... nothing happens. What now?', 0, halfheight -100 )
win .blit( our_game_display, origin )
WaitButton .draw( win, white )
SearchButton .draw( win, white)
YellHelpButton .draw( win, white)
pygame .display .update()
def search_choice():
our_game_display .fill( black )
text( 'So you decided to search.', 0, halfheight -100 )
win .blit( our_game_display, origin )
pygame .display .update()
def beginning_question():
our_game_display .fill( black )
text( 'The story of this game depends on your choices. Do you wish to play?', 0, halfheight -100 )
win .blit( our_game_display, origin )
PlayButton .draw( win, white )
pygame .display .update()
def begin_game(): ## call to start again
our_game_display .fill( black )
text( 'You wake up, or... at least you think you do. Even though your eyes are open,', 0, halfheight -300 )
text( "they still can't detect anything in the complete darkness that surrounds you.", 0, halfheight -270 )
text( 'What do you do?', 0, halfheight -210 )
win .blit( our_game_display, origin )
SitWaitButton .draw( win, white )
SearchButton .draw( win, white )
YellHelpButton .draw( win, white )
pygame .display .update()
## game loop .. color, (x), y, msg
PlayButton = button( black, 0, halfheight, "Let's play." )
SitWaitButton = button( black, 1, halfheight +50, 'Sit and wait...' )
SearchButton = button( black, 1, halfheight +100, 'Get up and try to search your surroundings' )
YellHelpButton = button( black, 1, halfheight +150, 'Yell to see if anyone is there' )
WaitButton = button( black, 1, halfheight +200, 'Keep waiting...' )
Wait2Button = button( black, 1, halfheight +250, 'Wait a little more...' )
Wait3Button = button( black, 1, halfheight +200, 'Wait a bit more...' )
Yell2Button = button( black, 1, halfheight +150, 'Yell again' )
while True:
if yell2_option == 'Go': yell_choice_2()
elif yell_option == 'Go': yell_choice()
elif search_option == 'Go': search_choice()
elif wait3_option == 'Go': keep_waiting_3()
elif wait2_option == 'Go': keep_waiting_2()
elif wait_option == 'Go': keep_waiting()
elif sit_option == 'Go': sit_choice()
elif game_begun == 'Go': begin_game()
else: beginning_question()
for event in pygame .event .get():
pos = pygame .mouse .get_pos()
if event .type == pygame .QUIT:
running = False
pygame .quit()
quit()
## yes & no buttons for beginning question
if event .type == pygame .MOUSEBUTTONDOWN: ## menu if/else
if PlayButton .isOver( pos ) and para['menu'] == True:
para['menu'] = False
game_begun = 'Go'
elif YellHelpButton .isOver( pos ) and para['menu'] == False and para['lock_1'] == True:
para['wait_lock2'] = True
para['wait_lock3'] = True
para['lock_1'] = False
para['yell_lock'] = False
yell_option = 'Go'
print( 'YellHelp button is working', para )
elif SitWaitButton .isOver( pos ) and para['menu'] == False and para['sit_lock'] == True:
para['wait_lock'] = False
para['sit_lock'] = False
sit_option = 'Go'
print( 'SitWait button is working', para )
elif SearchButton .isOver( pos ) and para['menu'] == False and para['lock_1'] == True:
para['wait_lock2'] = True
para['wait_lock3'] = True
para['lock_1'] = False
search_option = 'Go'
print( 'Search button is working', para )
elif WaitButton .isOver( pos ) and para['wait_lock'] == False:
para['lock_1'] = True
para['wait_lock'] = True
para['wait_lock2'] = False
wait_option = 'Go'
print( 'Wait button is working', para )
elif Wait2Button .isOver( pos ) and para['wait_lock2'] == False:
para['lock_1'] = True
para['wait_lock2'] = True
para['wait_lock3'] = False
wait2_option = 'Go'
print( 'Wait button 2 is working', para )
elif Wait3Button .isOver( pos ) and para['wait_lock3'] == False:
para['wait_lock2'] = True
para['wait_lock3'] = True
para['lock_1'] = False
wait3_option = 'Go'
print( 'Wait button 3 is working', para )
elif Yell2Button .isOver( pos ) and para['yell_lock'] == False:
para['yell_lock'] = True
yell2_option = 'Go'
print( 'Yell 2 button is working', para )
if event .type == pygame .MOUSEMOTION: ## first option buttons
PlayButton .color = black
YellHelpButton .color = black
SitWaitButton .color = black
SearchButton .color = black
WaitButton .color = black
Wait2Button .color = black
Wait3Button .color = black
Yell2Button .color = black
if PlayButton .isOver( pos ) and para['menu'] == True:
PlayButton .color = blue
if YellHelpButton .isOver( pos ): YellHelpButton .color = blue
if SitWaitButton .isOver( pos ): SitWaitButton .color = blue
if SearchButton .isOver( pos ): SearchButton .color = blue
if WaitButton .isOver( pos ): WaitButton .color = blue
if Wait2Button .isOver( pos ): Wait2Button .color = blue
if Wait3Button .isOver( pos ): Wait3Button .color = blue
if Yell2Button .isOver( pos ): Yell2Button .color = blue
Game2.py
from pygame_init import *
## module for helper functions
class button():
def __init__( self, color, x, y, text ):
self .color = color
self .x = x
self .y = y
self .width = 20
self .height = 10
self .text = text
def draw( self, win, outline = None ):
## Call this method to draw button on screen
if self .text != '':
text = buttonfont .render( self .text, 1, white )
self .width = text .get_width()
self .height = text .get_height()
## optional x parameter. If x pos given, use it, otherwise generate
if self .x == -1: ## -1 = left align
self .x = 20
elif self .x == 0: ## 0 = center align
self .x = halfwidth -( self .width /2 )
elif self .x == 1: ## 1 = right align
self .x = Width -self .width -20
if outline:
pygame .draw .rect( win, outline, ( self .x -12, self .y -12, self .width +24, self .height +24 ), 0 )
pygame .draw .rect( win, self .color, ( self .x -10, self .y -10, self .width +20, self .height +20 ), 0 )
if self .text != '':
win .blit( text, ( self .x, self .y ) )
def isOver( self, pos ):
## mouse position or a tuple of ( x, y ) coordinates
return pos[0] > self .x -13 and pos[0] < self .x -13 +self .width +26 \
and pos[1] > self .y -13 and pos[1] < self .y -13 +self .height +26
def text( text, xx, yy ): ## Function to position and draw text on screen
antialias = True
text_surface = textfont .render( text, antialias, white )
text_rect = text_surface .get_rect()
if abs( xx ) <= 1: ## generate x pos if -1, 0, 1
ww = text_surface .get_width() /2
## optional x parameter. If given, use it, otherwise justify
if xx == -1: ## -1 = left align
xx = ww +20
elif xx == 0: ## 0 = center align
xx = halfwidth
elif xx == 1: ## 1 = right align
xx = Width -ww -20
text_rect .center = ( xx, yy )
our_game_display .blit( text_surface, text_rect )
pygame_init.py
import pygame
## Module to hold all of the initial states of variables.
## Essentially globals, to be shared among the other modules.
pygame .init()
pygame .font .init() ## don't need to initialize font every turn, just do it once
screensize = Width, Height = 800, 700
halfwidth, halfheight = Width /2, Height /2
win = pygame .display .set_mode( screensize )
our_game_display = pygame .Surface( screensize )
origin = 0, 0 ## use variables for commonly used values
black = 0, 0, 0
blue = 0, 0, 139
white = 255, 255, 255
textfont = pygame .font .SysFont( 'comicsans', 28 )
buttonfont = pygame .font .SysFont( 'comicsans', 30 )
game_begun = 'Input' ## beginning choice
search_option = 'Input'
sit_option = 'Input'
yell_option = 'Input'
wait_option = 'Input'
wait2_option = 'Input'
wait3_option = 'Input'
yell2_option = 'Input'
para = { ## gamestate parameters
'menu': True,
'lock_1': True,
'sit_lock': True,
'wait_lock': True,
'wait_lock2': True,
'wait_lock3': True,
'yell_lock': True,
}
Change the color of 2 buttons in case of clicking on one of them
You can use the command
to call a function that sets the background color of the two buttons permanently (via configuring bg
property).
The following code changes the color of both buttons when the wrong button is pressed:
import tkinter as tk
def change_color(btn1, btn2):
btn1.configure(bg="green")
btn2.configure(bg="red")
root = tk.Tk()
btn = tk.Button(root,text="correct button")
btn.pack()
btn2 = tk.Button(root,text="wrong button", command=lambda: change_color(btn, btn2))
btn2.pack()
root.mainloop()
Changing the color of multiple buttons
SOLUTION
The path that contains the buttons siblings is self.parent.children
. With this information, you can change the background_color
of all the buttons.
EXAMPLE
def change_butt_color(self, *args):
for child in self.parent.children:
child.background_color = 1,1,1,1
self.background_color = 0,0,0,0
notice how the buttons aren't being searched for by ids
. Instead, self.parent.children
is used to find the button's parents children, which is, its self of course and the siblings of its self (self
).
Related Topics
How to Plot Nan Values as a Special Color with Imshow in Matplotlib
Moving X-Axis to the Top of a Plot in Matplotlib
Round Number to Nearest Integer
Which Tkinter Modules Were Renamed in Python 3
How to Access the Previous/Next Element in a for Loop
What Is the Fastest Way to Parse Large Xml Docs in Python
How to Print a List in Python "Nicely"
Dummy Variables When Not All Categories Are Present
Python: Download a File from an Ftp Server
Getting the Docstring from a Function
Advanced Nested List Comprehension Syntax
Prevent Pandas from Interpreting 'Na' as Nan in a String
Get Last "Column" After .Str.Split() Operation on Column in Pandas Dataframe
Find the Most Frequent Number in a Numpy Array
Typeerror: Unsupported Operand Type(S) for /: 'Str' and 'Str'