# Text class for Pygame [duplicate]

Failing to get a solution to my problem from other people, I got tired of waiting and wrote this (rather rushed) Text class to deal with the text problems I've been having in Pygame. I wanted the text to update itself, so that it would be unnecessary to keep track of its original position. After playing a lot with it, I found this solution:

class Text(object):

def __init__(self, value, size, color,
left_orientation=False,
font=None,
x=0, y=0,
top=None, bottom=None, left=None, right=None,
centerx=None, centery=None):

self._size = size
self._color = color
self._value = value
self._font = pygame.font.Font(font, self._size)
self.width, self.height = self._font.size(self._value)
self.left_orientation = left_orientation

self.image = self._create_surface()
self.rect = self.image.get_rect()
if x: self.rect.x = x
if y: self.rect.y = y
if top: self.rect.top = top
if bottom: self.rect.bottom = bottom
if left: self.rect.left = left
if right: self.rect.right = right
if centerx: self.rect.centerx = centerx
if centery: self.rect.centery = centery

def _create_surface(self):
return self._font.render(self._value, True, self._color)

def set_value(self, new_value):
if new_value != self._value:
self._value = new_value
self.image = self._create_surface()

new_rect = self.image.get_rect(x = self.rect.x, y = self.rect.y)
if self.left_orientation:
width_diff = new_rect.width - self.rect.width
new_rect.x = self.rect.x - width_diff
self.rect = new_rect

def set_position(self, x_or_x_and_y, y=None):
if y != None:
self.rect.x = x_or_x_and_y
self.rect.y = y
else:
self.rect.x = x_or_x_and_y[0]
self.rect.y = x_or_x_and_y[1]


So, if a text is supposed to increase to the left, all that I have to do is initialize a Text object with the left_orientation parameter set to True and, whatever the rect is, it will update itself to remain at it's original position.

Is this a good solution? If not, what would be a better one?

1. The Text._size member is only used to create the font, so there is no need to store it in the instance.

2. Why not make Text a subclass of pygame.sprite.Sprite so that you can draw it using a sprite group?

3. Lots of code is repeated betwen Text.__init__ and Text.set_value. Why not have the former call the latter?

4. The Text.__init__ constructor takes many keyword arguments, which you then apply to self.rect like this:

if top: self.rect.top = top
...


The first problem is that the test if top: means that you can't set top to zero. You should write something like this:

if top is not None: self.rect.top = top


But it would be much simpler to use Python's ** keyword argument mechanism to take any number of keyword arguments, and pass them all to Surface.get_rect.

Applying all these improvements yields the following:

class Text(pygame.sprite.Sprite):
def __init__(self, text, size, color, font=None, **kwargs):
super(Text, self).__init__()
self.color = color
self.font = pygame.font.Font(font, size)
self.kwargs = kwargs
self.set(text)

def set(self, text):
self.image = self.font.render(str(text), 1, self.color)
self.rect = self.image.get_rect(**self.kwargs)