3

I'm learning to use pygame and I have some problems with rendering text.

The simplified code I'm working with is like this:

import pygame

sizex =200; sizey =200

pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode((sizex,sizey))
myfont = pygame.font.Font(None, 32)

score=pygame.Rect(100,100,100,50)

screen.fill((255,255,255))
pygame.draw.rect(screen, (0,250,0), (10,10,10,10), 2)
pygame.display.update()

for i in xrange(0,1000): 
    msElapsed = clock.tick(2)
    text="I = %d" %i
    label = myfont.render(text, 1, (0,0,250))
    screen.blit(label, (100, 100))

    pygame.display.update(score)

I want update only the part of screen which contains the textbox. But this code is not doing this. The texts overwrite themselves and become unreadable after a while.

What am I doing wrong?

David Sousa
  • 383
  • 2
  • 13

1 Answers1

1

The problem is that when you blit a text, the background of the text is transparent (note that this important for example when you want to have a background image). You have to "clear" the rectangle first, and then blit the text. In your case, as you are using a plain color as background, you can do:

for i in xrange(0,1000): 
    msElapsed = clock.tick(2)
    text="I = %d" %i
    label = myfont.render(text, 1, (0,0,250))
    screen.fill((255,255,255), rect=label.get_rect(topleft=(100,100)))
    screen.blit(label, (100, 100))

    pygame.display.update(score)

If you use an image instead of a solid color, you would have to blit the appropriate area of the background.

Edit:

As indicated by Bartlomiej, if the new string is sorter than the former, it will not get erased completely. You may just clear the whole screen each time, or try to figure out how to clear exactly what you need to clear, for example, storing the area of the previous blit:

previous_rect = None
for i in xrange(0,1000): 
    msElapsed = clock.tick(2)
    text="I = %d" %i
    if prev_rect:
        screen.fill((255,255,255), rect=prev_rect)
    label = myfont.render(text, 1, (0,0,250))
    previous_rect = label.get_rect(topleft=(100,100))
    screen.blit(label, (100, 100))

    pygame.display.update(score)
jdehesa
  • 58,456
  • 7
  • 77
  • 121
  • 1
    One more problem, if the old string is longer than the new string, it will not be overwritten. It is better to draw the whole screen every frame. – Bartlomiej Lewandowski Oct 08 '14 at 15:02
  • So, I think the easiest way to do I want is simplely using a background color in the rectangle with the text. Is there any way to do that? – David Sousa Oct 08 '14 at 15:12
  • @DavidSousa Indeed. In the [`render` method documentation](http://www.pygame.org/docs/ref/font.html#pygame.font.Font.render) says that you can pass a `background` parameter to put a solid background color. However, note that you may still have problems if texts are not exactly the same size. – jdehesa Oct 08 '14 at 15:15
  • I get it, I just should draw an white retangle above the text area before bliting the text again, at every iteration. Problem solved! – David Sousa Oct 08 '14 at 15:15
  • @javidcf the `score` rectangle has fixed size and is always larger than the text. – David Sousa Oct 08 '14 at 15:16
  • @DavidSousa Alright, you mean you fill the whole `score` rectangle each time. Yes, that's even better. – jdehesa Oct 08 '14 at 15:21
  • 1
    Just for the curious, the whole code I'm working is this: http://pastebin.com/1y6quQKw It is an integrator for Newton laws of motion that displays the calculated positions. – David Sousa Oct 08 '14 at 15:32