Work with text

In pygame, text cannot be written directly to the screen. The first step is to create a Font object with a given font size. The second step is to render the text into an image with a given color. The third step is to blit the image to the screen. These are the steps:

font = pygame.font.SysFont(None, 24)
img = font.render('hello', True, BLUE)
screen.blit(img, (20, 20))

Once the font is created, its size cannot be changed. A Font object is used to create a Surface object from a string. Pygame does not provide a direct way to write text onto a Surface object. The method render() must be used to create a Surface object from the text, which then can be blit to the screen. The method render() can only render single lines. A newline character is not rendered.

Initialize a font

Initializing the font can take a few seconds. On a MacBook Air the the creation of a system Font object:

t0 = time.time()
font = pygame.font.SysFont(None, 48)
print('time needed for Font creation :', time.time()-t0)

took more then 8 seconds:

time needed for Font creation : 8.230187892913818

The function get_fonts() returns a list of all installed fonts. The following code checks what fonts are on your system and how many, and prints them to the console:

fonts = pygame.font.get_fonts()
print(len(fonts))
for f in fonts:
    print(f)

You will get something like this:

344
bigcaslonttf
silomttf
sfnsdisplayblackitalicotf
chalkdusterttf
...

Render the text

The font object can render a given text into an image. In the example below, we place a blue bounding rectangle around that text image:

img = font.render(sysfont, True, RED)
rect = img.get_rect()
pygame.draw.rect(img, BLUE, rect, 1)

We then create two more fonts, Chalkduster and Didot at a size of 72 points. We render a text with both fonts:

font1 = pygame.font.SysFont('chalkduster.ttf', 72)
img1 = font1.render('chalkduster.ttf', True, BLUE)

font2 = pygame.font.SysFont('didot.ttc', 72)
img2 = font2.render('didot.ttc', True, GREEN)

Finally the text images are blit to the screen like regular images:

screen.fill(background)
screen.blit(img, (20, 20))
screen.blit(img1, (20, 50))
screen.blit(img2, (20, 120))
pygame.display.update()

This is the result:

../_images/text1.png

Here is the full code.

"""Draw text to the screen."""
import pygame
from pygame.locals import *
import time
 
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
GRAY = (200, 200, 200)

pygame.init()
screen = pygame.display.set_mode((640, 240))

sysfont = pygame.font.get_default_font()
print('system font :', sysfont)

t0 = time.time()
font = pygame.font.SysFont(None, 48)
print('time needed for Font creation :', time.time()-t0)

img = font.render(sysfont, True, RED)
rect = img.get_rect()
pygame.draw.rect(img, BLUE, rect, 1)

font1 = pygame.font.SysFont('chalkduster.ttf', 72)
img1 = font1.render('chalkduster.ttf', True, BLUE)

font2 = pygame.font.SysFont('didot.ttc', 72)
img2 = font2.render('didot.ttc', True, GREEN)

fonts = pygame.font.get_fonts()
print(len(fonts))
for i in range(7):
    print(fonts[i])

running = True
background = GRAY
while running:
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False

    screen.fill(background)
    screen.blit(img, (20, 20))
    screen.blit(img1, (20, 50))
    screen.blit(img2, (20, 120))
    pygame.display.update()

pygame.quit()

Edit text with the keybord

The keyboard event can be used to edit a text. First we create a text which we save in a string variable text and which we render to an image:

text = 'this text is editable'
font = pygame.font.SysFont(None, 48)
img = font.render(text, True, RED)

Then we define the bounding rectangle and furthermore a cursor rectangle which is juxtaposed to the text bounding rectangle:

rect = img.get_rect()
rect.topleft = (20, 20)
cursor = Rect(rect.topright, (3, rect.height))

Inside the event loop we watch out for KEYDOWN events. If the key press is a BACKSPACE and the lenght of the string is larger than 0, then we remove the last character, else we append the new character to the text variable:

if event.type == KEYDOWN:
    if event.key == K_BACKSPACE:
        if len(text)>0:
            text = text[:-1]
    else:
        text += event.unicode

Then we render the modified text, update the bounding rectangle, and place the cursor box at the end of the updated bounding rectangle:

img = font.render(text, True, RED)
rect.size=img.get_size()
cursor.topleft = rect.topright

Add a blinking cursor

In order to make the cursor more visible, we let it blink every 0.5 seconds. We do this using the time.time() floating point value:

screen.fill(background)
screen.blit(img, rect)
if time.time() % 1 > 0.5:
    pygame.draw.rect(screen, RED, cursor)
pygame.display.update()

This is the result:

../_images/text2.png

Here is the full code.

"""Edit text with the keyboard."""
import pygame
from pygame.locals import *
import time
 
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GRAY = (200, 200, 200)

pygame.init()
screen = pygame.display.set_mode((640, 240))

text = 'this text is editable'
font = pygame.font.SysFont(None, 48)
img = font.render(text, True, RED)

rect = img.get_rect()
rect.topleft = (20, 20)
cursor = Rect(rect.topright, (3, rect.height))

running = True
background = GRAY

while running:
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False
        
        if event.type == KEYDOWN:
            if event.key == K_BACKSPACE:
                if len(text)>0:
                    text = text[:-1]
            else:
                text += event.unicode
            img = font.render(text, True, RED)
            rect.size=img.get_size()
            cursor.topleft = rect.topright
    
    screen.fill(background)
    screen.blit(img, rect)
    if time.time() % 1 > 0.5:
        pygame.draw.rect(screen, RED, cursor)
    pygame.display.update()

pygame.quit()