How can I create a text input box with Pygame? How can I create a text input box with Pygame? python python

How can I create a text input box with Pygame?


You can define a rect as the area of the input box. If a pygame.MOUSEBUTTONDOWN event occurs, use the colliderect method of the input_box rect to check if it collides with the event.pos and then activate it by setting a active variable to True.

If the box is active you can type something and Pygame will generate pygame.KEYDOWN events which have a unicode attribute that you can simply add to a string, e.g. text += event.unicode. If the user presses enter, you can do something with the text string (in the example I just print it) and reset it to ''.

import pygame as pgdef main():    screen = pg.display.set_mode((640, 480))    font = pg.font.Font(None, 32)    clock = pg.time.Clock()    input_box = pg.Rect(100, 100, 140, 32)    color_inactive = pg.Color('lightskyblue3')    color_active = pg.Color('dodgerblue2')    color = color_inactive    active = False    text = ''    done = False    while not done:        for event in pg.event.get():            if event.type == pg.QUIT:                done = True            if event.type == pg.MOUSEBUTTONDOWN:                # If the user clicked on the input_box rect.                if input_box.collidepoint(event.pos):                    # Toggle the active variable.                    active = not active                else:                    active = False                # Change the current color of the input box.                color = color_active if active else color_inactive            if event.type == pg.KEYDOWN:                if active:                    if event.key == pg.K_RETURN:                        print(text)                        text = ''                    elif event.key == pg.K_BACKSPACE:                        text = text[:-1]                    else:                        text += event.unicode        screen.fill((30, 30, 30))        # Render the current text.        txt_surface = font.render(text, True, color)        # Resize the box if the text is too long.        width = max(200, txt_surface.get_width()+10)        input_box.w = width        # Blit the text.        screen.blit(txt_surface, (input_box.x+5, input_box.y+5))        # Blit the input_box rect.        pg.draw.rect(screen, color, input_box, 2)        pg.display.flip()        clock.tick(30)if __name__ == '__main__':    pg.init()    main()    pg.quit()

Here's an object-oriented variant that allows you to easily create multiple input boxes:

import pygame as pgpg.init()screen = pg.display.set_mode((640, 480))COLOR_INACTIVE = pg.Color('lightskyblue3')COLOR_ACTIVE = pg.Color('dodgerblue2')FONT = pg.font.Font(None, 32)class InputBox:    def __init__(self, x, y, w, h, text=''):        self.rect = pg.Rect(x, y, w, h)        self.color = COLOR_INACTIVE        self.text = text        self.txt_surface = FONT.render(text, True, self.color)        self.active = False    def handle_event(self, event):        if event.type == pg.MOUSEBUTTONDOWN:            # If the user clicked on the input_box rect.            if self.rect.collidepoint(event.pos):                # Toggle the active variable.                self.active = not self.active            else:                self.active = False            # Change the current color of the input box.            self.color = COLOR_ACTIVE if self.active else COLOR_INACTIVE        if event.type == pg.KEYDOWN:            if self.active:                if event.key == pg.K_RETURN:                    print(self.text)                    self.text = ''                elif event.key == pg.K_BACKSPACE:                    self.text = self.text[:-1]                else:                    self.text += event.unicode                # Re-render the text.                self.txt_surface = FONT.render(self.text, True, self.color)    def update(self):        # Resize the box if the text is too long.        width = max(200, self.txt_surface.get_width()+10)        self.rect.w = width    def draw(self, screen):        # Blit the text.        screen.blit(self.txt_surface, (self.rect.x+5, self.rect.y+5))        # Blit the rect.        pg.draw.rect(screen, self.color, self.rect, 2)def main():    clock = pg.time.Clock()    input_box1 = InputBox(100, 100, 140, 32)    input_box2 = InputBox(100, 300, 140, 32)    input_boxes = [input_box1, input_box2]    done = False    while not done:        for event in pg.event.get():            if event.type == pg.QUIT:                done = True            for box in input_boxes:                box.handle_event(event)        for box in input_boxes:            box.update()        screen.fill((30, 30, 30))        for box in input_boxes:            box.draw(screen)        pg.display.flip()        clock.tick(30)if __name__ == '__main__':    main()    pg.quit()

There are also third party modules available like pygame_textinput.


Use the KEYDOWN event to get the input from the keyboard (see pygame.event). The key that was pressed can be obtained from the key attribute of the pygame.event.Event object. unicode contains a single character string that is the fully translated character. Add the character to the text when a key is pressed.
Two special keys need to be dealt with. If RETURN is pressed, the input is finished. If BACKSPACE is pressed, the last character of the input text must be removed:

repl.it/@Rabbid76/PyGame-TextInput

import pygamepygame.init()window = pygame.display.set_mode((500, 200))clock = pygame.time.Clock()font = pygame.font.SysFont(None, 100)text = ""input_active = Truerun = Truewhile run:    clock.tick(60)    for event in pygame.event.get():        if event.type == pygame.QUIT:            run = False        elif event.type == pygame.MOUSEBUTTONDOWN:            input_active = True            text = ""        elif event.type == pygame.KEYDOWN and input_active:            if event.key == pygame.K_RETURN:                input_active = False            elif event.key == pygame.K_BACKSPACE:                text =  text[:-1]            else:                text += event.unicode        window.fill(0)        text_surf = font.render(text, True, (255, 0, 0))        window.blit(text_surf, text_surf.get_rect(center = window.get_rect().center))        pygame.display.flip()pygame.quit()exit()

Use the algorithm in a pygame.sprite.Sprite class. Handle the event in the update method.Determine whether the mouse clicks in the text entry field with collidepoint (see How to detect when a rectangular object, image or sprite is clicked) and activate the text input box:

class TextInputBox(pygame.sprite.Sprite):    # [...]    def update(self, event_list):        for event in event_list:            if event.type == pygame.MOUSEBUTTONDOWN and not self.active:                self.active = self.rect.collidepoint(event.pos)            if event.type == pygame.KEYDOWN and self.active:                if event.key == pygame.K_RETURN:                    self.active = False                elif event.key == pygame.K_BACKSPACE:                    self.text = self.text[:-1]                else:                    self.text += event.unicode                self.render_text()

Pass the list of events to the update method of the Group that contains the Sprite:

event_list = pygame.event.get()for event in event_list:    if event.type == pygame.QUIT:        run = Falsegroup.update(event_list)

Minimal example: repl.it/@Rabbid76/PyGame-SpriteTextInput

import pygameclass TextInputBox(pygame.sprite.Sprite):    def __init__(self, x, y, w, font):        super().__init__()        self.color = (255, 255, 255)        self.backcolor = None        self.pos = (x, y)         self.width = w        self.font = font        self.active = False        self.text = ""        self.render_text()    def render_text(self):        t_surf = self.font.render(self.text, True, self.color, self.backcolor)        self.image = pygame.Surface((max(self.width, t_surf.get_width()+10), t_surf.get_height()+10), pygame.SRCALPHA)        if self.backcolor:            self.image.fill(self.backcolor)        self.image.blit(t_surf, (5, 5))        pygame.draw.rect(self.image, self.color, self.image.get_rect().inflate(-2, -2), 2)        self.rect = self.image.get_rect(topleft = self.pos)    def update(self, event_list):        for event in event_list:            if event.type == pygame.MOUSEBUTTONDOWN and not self.active:                self.active = self.rect.collidepoint(event.pos)            if event.type == pygame.KEYDOWN and self.active:                if event.key == pygame.K_RETURN:                    self.active = False                elif event.key == pygame.K_BACKSPACE:                    self.text = self.text[:-1]                else:                    self.text += event.unicode                self.render_text()pygame.init()window = pygame.display.set_mode((500, 200))clock = pygame.time.Clock()font = pygame.font.SysFont(None, 100)text_input_box = TextInputBox(50, 50, 400, font)group = pygame.sprite.Group(text_input_box)run = Truewhile 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()


You can find a great module for Pygame text input here.

I have been using it for a while and I really like it. A tutorial how to use it is included in the description.

However, I have added the possibility to draw a (coloured) rectangle around the text, by adding a rect and a rect_color parameter to the *_init_() function and adding

if self.rect != None:    pygame.draw.rect(screen, self.rect_color, self.rect)    #screen is my pygame display surface

to the update(self, events) function.