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 = 600display_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 moduleimport pygame# initialisationpygame.init()# setting up window sizedisplay_width = 600display_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 framefont = 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 loopsprites = 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:
Output: when hovered on buttons and they are changing colour of themselves
