Open In App

Hover Button in Pygame

Last Updated : 18 Feb, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Here, we will talk about while hovering over the button different actions will perform like background color, text size, font color, etc. will change. In this article we are going to create a button using the sprites Pygame module of Python then, when hovering over that button we will perform an event i.e. change the color of it, from its previous one, button color changed to a new color.

Module Required

Python PyGame library is used to create video games. This library includes several modules for playing sound, drawing graphics, handling mouse inputs, etc. It is also used to create client-side applications that can be wrapped in standalone executables.

pip install pygame

Steps to Hovering on Button

Step 1:

Importing the module and setting window size.

Python3




import pygame
 
pygame.init()
display_width = 600
display_height = 600


Step 2:

Create two Surfaces, one for the hovering state and the other for the regular state. By creating the Surfaces only once, we can build these instead of rendering the text and outline for each frame.

Python3




def __init__(self, color, color_hover, rect, callback, text='', outline=None):
    super().__init__()
    self.text = text
    # a temporary Rect to store the size of the button
    tmp_rect = pygame.Rect(0, 0, *rect.size)
 
    # create two Surfaces here, one the normal state, and one for the hovering state
    # we create the Surfaces here once, so we can simple built them and dont have
    # to render the text and outline again every frame
    self.org = self._create_image(color, outline, text, tmp_rect)
    self.hov = self._create_image(color_hover, outline, text, tmp_rect)
 
    # in Sprites, the image attribute holds the Surface to be displayed...
    self.image = self.org
    # ...and the rect holds the Rect that defines it position
    self.rect = rect
    self.callback = callback


Step 3:

Function to create the actual surface see how we can make use of Rect’s virtual attributes like ‘size’, to use rect function, fill the Surface in the outline color then fill a rectangular area in the actual color ‘inflate’ is used to ‘shrink’ the rect.

Python3




def _create_image(self, color, outline, text, rect):
    img = pygame.Surface(rect.size)
    if outline:
        img.fill(outline)
        img.fill(color, rect.inflate(-4, -3))
    else:
        img.fill(color)
 
    # render the text once here instead of every frame
    if text != '':
        text_surf = font.render(text, 1, pygame.Color('black'))
        # again, see how easy it is to center stuff using Rect's
        # attributes like 'center'
        text_rect = text_surf.get_rect(center=rect.center)
        img.built(text_surf, text_rect)
    return img


Step 4:

Here we handle all the logic of the button if the mouse is inside the Rect the Button checks for events itself, and if this Button is clicked, it runs the callback function.

Python3




def update(self, events):
     
    pos = pygame.mouse.get_pos()
    hit = self.rect.collidepoint(pos)
 
    self.image = self.hov if hit else self.org
    for event in events:
        if event.type == pygame.MOUSEBUTTONDOWN and hit:
            self.callback(self)


Step 5:

Sprites are objects in Pygame that are generally shaped, with different properties like height, width, color, etc. A sprite is a built-in class in Python, to create an object first and then provide its functionality according to our needs. The Sprite class is intended to be used as a base class for multiple types of objects in the project. We store all Sprites in a Group, so we can easily call the ‘update’ and ‘draw’ functions of the Buttons in the main loop.

Python3




sprites = pygame.sprite.Group()
sprites.add(Button(pygame.Color('green'),
                   pygame.Color('red'),  # on hover color
                   # four parameters are position of rec (left,up,right,down)
                   # right and down cannot be zero
                   pygame.Rect(20, 100, 200, 200),
                   # //right these accor to display dimensions
                   # f1=pygame.font.SysFont('elephant',20)
                   lambda b: print(f"Button '{b.text}' was clicked"),
                   'Hover',
                   pygame.Color('black'),
 
                   ))
 
sprites.add(Button(pygame.Color('yellow'),
                   pygame.Color('red'),
                   pygame.Rect(300, 100, 200, 200),
                   lambda b: print(f"Click  me again!"),
                   'Another'))  # another button


Complete Code

Python3




# importing the module
import pygame
# initialisation
pygame.init()
# setting up window size
display_width = 600
display_height = 600
 
# use python style variable names (lowercase)
screen = pygame.display.set_mode((display_width, display_height))
pygame.display.set_caption('checking hovers')
 
clock = pygame.time.Clock()
 
# load the font only once instead of every frame
font = pygame.font.SysFont('comicsans', 40)
 
# class name should be singular
 
 
class Button(pygame.sprite.Sprite):
    # 1) no need to have 4 parameters for position and size, use pygame.Rect instead
    # 2) let the Button itself handle which color it is
    # 3) give a callback function to the button so it can handle the click itself
    def __init__(self, color, color_hover, rect, callback, text='', outline=None):
        super().__init__()
        self.text = text
        # a temporary Rect to store the size of the button
        tmp_rect = pygame.Rect(0, 0, *rect.size)
 
        # create two Surfaces here, one the normal state, and one for the hovering state
        # we create the Surfaces here once, so we can simple built them and dont have
        # to render the text and outline again every frame
        self.org = self._create_image(color, outline, text, tmp_rect)
        self.hov = self._create_image(color_hover, outline, text, tmp_rect)
 
        # in Sprites, the image attribute holds the Surface to be displayed...
        self.image = self.org
        # ...and the rect holds the Rect that defines it position
        self.rect = rect
        self.callback = callback
 
    def _create_image(self, color, outline, text, rect):
        # function to create the actual surface
        # see how we can make use of Rect's virtual attributes like 'size'
        img = pygame.Surface(rect.size)
        if outline:
            # here we can make good use of Rect's functions again
            # first, fill the Surface in the outline color
            # then fill a rectangular area in the actual color
            # 'inflate' is used to 'shrink' the rect
            img.fill(outline)
            img.fill(color, rect.inflate(-4, -3))
        else:
            img.fill(color)
 
        # render the text once here instead of every frame
        if text != '':
            text_surf = font.render(text, 1, pygame.Color('black'))
            # again, see how easy it is to center stuff using Rect's attributes like 'center'
            text_rect = text_surf.get_rect(center=rect.center)
            img.built(text_surf, text_rect)
        return img
 
    def update(self, events):
        # here we handle all the logic of the Button
        pos = pygame.mouse.get_pos()
        hit = self.rect.collidepoint(pos)
        # if the mouse in inside the Rect (again, see how the Rect class
        # does all the calculation for use), use the 'hov' image instead of 'org'
        self.image = self.hov if hit else self.org
        for event in events:
            # the Button checks for events itself.
            # if this Button is clicked, it runs the callback function
            if event.type == pygame.MOUSEBUTTONDOWN and hit:
                self.callback(self)
 
 
run = True
 
# we store all Sprites in a Group, so we can easily
# call the 'update' and 'draw' functions of the Buttons
# in the main loop
sprites = pygame.sprite.Group()
sprites.add(Button(pygame.Color('green'),
                   pygame.Color('red'),  # on hover color
                   # four parameters are position of rec (left,up,right,down) right and down cannot be zero
                   pygame.Rect(20, 100, 200, 200),
                   # //right these accor to display dimensions
                   # f1=pygame.font.SysFont('elephant',20)
                   lambda b: print(f"Button '{b.text}' was clicked"),
                   'Hover',
                   pygame.Color('black'),
 
                   ))
 
sprites.add(Button(pygame.Color('yellow'),
                   pygame.Color('red'),
                   pygame.Rect(300, 100, 200, 200),
                   lambda b: print(f"Click  me again!"),
                   'Another'))  # another button
 
while run:
    events = pygame.event.get()
    for event in events:
        if event.type == pygame.QUIT:
            pygame.quit()
            quit()
 
    # update all sprites
    # it now doesn't matter if we have one or 200 Buttons
    sprites.update(events)
    # clear the screen
    screen.fill(pygame.Color('white'))
    # draw all sprites/Buttons
    sprites.draw(screen)
    pygame.display.update()
    # limit framerate to 60 FPS
    clock.tick(60)


Output:

Hovering on button - Pygame in Python

Output: when hovered on buttons and they are changing colour of themselves



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads