[Rod Stephens Books]
Index Books Python Examples About Rod Contact
[Mastodon] [Bluesky]
[Build Your Own Ray Tracer With Python]

[Beginning Database Design Solutions, Second Edition]

[Beginning Software Engineering, Second Edition]

[Essential Algorithms, Second Edition]

[The Modern C# Challenge]

[WPF 3d, Three-Dimensional Graphics with WPF and C#]

[The C# Helper Top 100]

[Interview Puzzles Dissected]

Title: Draw aligned text with Python and Pygame

[Text aligned in various ways with Python and Pygame]

Unfortunately, Pygame doesn't make it easy to position and draw text. To display text, you need to first render it onto its own surface and then blit the surface onto another surface where you want to display it. This example shows how you can do that with a minimum of fuss.

This program defines two sprite classes: TextSprite to display text and CircleSprite to display circles. The TextSprite class's draw method calls draw_image to draw the text with the proper alignment.

TextSprite

Here's the TextSprite class, which draws text.

class TextSprite: '''Sprite to display text.''' def __init__(self, text, position, alignment, font, color, antialias=False, background=None): '''Prepare the text surface.''' # Validate the alignment. if alignment not in 'nw,n,ne,e,se,s,sw,w,c': raise ValueError(f'Unknown TextSprite alignment {alignment}') # Save the positioning parameters. self.position = position self.alignment = alignment # Draw the text onto its own surface. self.surface = font.render(text, antialias, color, background) def update(self, elapsed_seconds, bounds): pass def draw(self, surface): '''Draw the text.''' draw_image(surface, self.surface, self.position, self.alignment)

The class's constructor verifies that the alignment property is one of the allowed compass directions nw, n, ne, e, se, s, sw, w, or c. If alignment has some other value, the code throws a temper tantrum by raising a ValueError.

Next, the constructor saves the position and alignment values. The alignment tells what part of the text should be placed at the position. For example, if alignment is nw, then the upper left corner of the text should be placed at position.

The constructor finishes by calling font.render to render the text onto its own surface.

The draw method calls draw_image to draw the rendered text onto the main drawing surface. I'll describe draw_image a bit later.

CircleSprite

Here's how the CircleSprite class draws a circle.

class CircleSprite: '''Sprite to display a circle.''' def __init__(self, center, radius, fill_color, outline_color): '''Save the drawing properties.''' self.center = center self.radius = radius self.fill_color = fill_color self.outline_color = outline_color def update(self, elapsed_seconds, bounds): pass def draw(self, surface): '''Draw the circle.''' pygame.draw.circle(surface, self.fill_color, self.center, self.radius) pygame.draw.circle(surface, self.outline_color, self.center, self.radius, width=1)

The constructor saves the circle's center, radius, and colors. The draw method fills the circle and then outlines it.

draw_image

The draw_image function is where most of the magic happens. It uses the following code to draw one surface onto another with a desired alignment.

def draw_image(surface, image, position, alignment): '''Draw the image on the surface with the indicated alignment.''' # See where we should draw it. if alignment == 'nw': rect = image.get_rect(topleft=position) elif alignment == 'n': rect = image.get_rect(midtop=position) elif alignment == 'ne': rect = image.get_rect(topright=position) elif alignment == 'w': rect = image.get_rect(midleft=position) elif alignment == 'c': rect = image.get_rect(center=position) elif alignment == 'e': rect = image.get_rect(midright=position) elif alignment == 'sw': rect = image.get_rect(bottomleft=position) elif alignment == 's': rect = image.get_rect(midbottom=position) elif alignment == 'se': rect = image.get_rect(bottomright=position) else: raise ValueError(f'Unknown draw_image alignment {alignment}') # Draw the image onto the surface in the rectangle. surface.blit(image, rect)

This code uses a series of if elif statements to see which alignment we want. As with the TextSprite class, the alignment tells what part of the image should be placed at the position. For example, if alignment is nw, then the upper left corner of the image should be placed at position.

For each alignment value, the code call's the image object's get_rect method. That method returns a rectangle representing the image object's size and position. The different parameters passed into get_rect determine the rectangle's position. For example, the first case sets topleft=position to tell get_rect to create a rectangle big enough to hold the image and positioned so the rectangle's top left corner is at position.

After the if elif statements get the desired target rectangle, the code calls the surface object's blit method to draw the image onto the surface.

Main Program

Here's how the main program draws text aligned in the northwest.

# NW rect = pygame.Rect(margin, margin, wid, hgt) position = rect.topleft self.all_sprites.insert(0, TextSprite('Northwest', position, 'nw', font, text_color, True, pygame.Color('pink'))) self.all_sprites.append( CircleSprite(position, radius, fill_color, outline_color))

This code creates a rectangle where it will position the text. (This rectangle is just used to space the text evenly across the window.) It then uses the rectangle's rect.topleft property to get the position of the rectangle's top left corner.

The program then creates a TextSprite with alignment set to nw and position set to the rectangle's top left corner so, when the sprite displays its text, it puts the text's northwest corner at the rectangle's upper left corner. The code inserts the new sprite at the beginning of the all_sprites list so it will be drawn before (and therefore below) the circle sprites.

Next, the code creates a CircleSprite to mark the text's position. It appends that sprite to the end of the all_sprites list so it is drawn after (and therefore above) any of the text sprites.

The code that creates the other sprites is similar. Download the example to see the details.

Conclusion

The draw_image function makes it relatively easy to draw one surface on another, positioning it with respect to a specified point. The TextSprite class uses that function to draw aligned text. Probably the hardest part of the whole thing is remembering how the alignment and position determine how the text is arranged.

Download the example to experiment with it and to see additional details.

© 2025 Rocky Mountain Computer Consulting, Inc. All rights reserved.