Hover Button in Pygame

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
| importpygamepygame.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)    ifoutline:        img.fill(outline)        img.fill(color, rect.inflate(-4, -3))    else:        img.fill(color)    # render the text once here instead of every frame    iftext !='':        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)    returnimg | 
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
| defupdate(self, events):        pos =pygame.mouse.get_pos()    hit =self.rect.collidepoint(pos)    self.image =self.hov ifhit elseself.org    forevent inevents:        ifevent.type==pygame.MOUSEBUTTONDOWN andhit:            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)                   lambdab: 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),                   lambdab: print(f"Click  me again!"),                   'Another'))  # another button | 
Complete Code
Python3
| # importing the moduleimportpygame# 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 singularclassButton(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)        ifoutline:            # 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        iftext !='':            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)        returnimg    defupdate(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 ifhit elseself.org        forevent inevents:            # the Button checks for events itself.            # if this Button is clicked, it runs the callback function            ifevent.type==pygame.MOUSEBUTTONDOWN andhit:                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)                   lambdab: 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),                   lambdab: print(f"Click  me again!"),                   'Another'))  # another buttonwhilerun:    events =pygame.event.get()    forevent inevents:        ifevent.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
 
				 
					


