Adding Text onto a Rect [duplicate] - python

This question already has an answer here:
I need to add text to my rectangles, how would I do this?
(1 answer)
Closed 2 years ago.
So I have defined a function Meteor and set up the dimensions and where it will appear on the screen.
def Meteor(Meteorx, Meteory, Meteorw, Meteorh, colour):
pygame.draw.rect(Screen, colour, [Meteorx,Meteory, Meteorw, Meteorh])
but I wanted to add text to it but I can't work out how to blit it onto a rectangle (note: I have tried to play around with font.render etc). Am I going the right way about this or is there a simpler way than putting it onto the rect surface.
Source code https://github.com/WamblyTK/Word-Blaster/blob/master/Full%20Draft%20%231

First you'll need a pygame.font, which can be created by pygame.font.SysFont() or pygame.font.Font. e.g.:
import pygame.font
font = pygame.font.SysFont('Times New Roman', 30)
With the font object a text can be rendered by .render(). The result is a pygame.Surface object.
If you want you can scale the surface to a certain size, by pygame.transform.smoothscale.
Finally the text can be drawn to the surface by blit. e.g.:
def Meteor(Meteorx, Meteory, Meteorw, Meteorh, colour):
text = font.render('test text', False, colour)
text = pygame.transform.smoothscale(text.convert(), (Meteorw, Meteorh))
Screen.blit(text, (Meteorx, Meteory))
As mentioned in the comment below it is easier to use pygame.freetype. e.g.:
import pygame.freetype
font = pygame.freetype.SysFont('Times New Roman', 30)
def Meteor(Meteorx, Meteory, Meteorw, Meteorh, colour):
font.render_to(Screen, (Meteorx, Meteory), 'test text', colour, size=Meteorw)

Related

python text changer while the code is running in pygame [duplicate]

I'm fairly new to pygame and ive hit my first stump which I cannot find an answer for..
After blitting text, then changing the string for the same variable, the game instead of replacing the original text with the new, overlaps the two texts..?
You have to erase the old text first. Surfaces created by Font.render are ordinary surfaces. Once a Surface is blit, its contents become part of the destination surface, and you have to manipulate the destination surface to erase whatever was blit from the source surface.
One way to erase the destination surface is to blit a background surface onto it. The background surface is what the destination surface would look like without anything like text or sprites on it. Another way is to fill the surface with a solid color:
# pygame initialization goes here
screen = pygame.display.get_surface()
font = pygame.font.Font(None, 40)
font_surface = font.render("original", True, pygame.Color("white"));
screen.blit(surface, (0, 0))
screen.fill(pygame.Color("black")) # erases the entire screen surface
font_surface = font.render("edited", True, pygame.Color("white"));
screen.blit(surface, (0, 0))
You could also overwrite your text.
Like this:
label = myfont.render("Text", 0, (255,255,0))
screen.blit(label, (100, 100))
if x: //Parameter you check before overwrite
label = myfont.render("Text", 0, BACKGROUND_COLOR)
screen.blit(label, (100, 100))
There can be an other solution, even if it's not very different.
The previous answer erases all the screen, but you can erase just your text.
If it's written on an image, you will replace just a part of the image, by getting the text size and blitting the corresponding image part (pygame.surface.subsurface function).
Or if it's not, you can just fill a part of the screen.
In this case you will just erase your text.

How to display different text on different rectangles in pygame?

I have created a Pygame application where I have about 25 rectangles. I want to display 25 different text values (which is a numerical value but typecasted in str- I mention this because I believe we need string in the first argument) at the center of the rectangle. I have imported a csv file that contains data.
def draw_point(text, pos):
font = pygame.font.SysFont(None, 20)
img = font.render(text, True, (0,0,0))
window.blit(img, pos)
def loop_func():
count = 0
while count < total_length:
data = data_pass[count] # data_pass is an empty list
pygame.draw.rect(window, (255,255,255), (20, 20, width, height))
draw_point(data, (width // 2, height // 2))
According to the loop_func() function, the variable 'data' should be updated with a new value in every loop, and it is updating because I checked with the print() function. But when I pass the variable to the draw_point() function, it seems the function does not display the desired value. This is my output:
It is actually 25 different rectangles with an almost similar background color. I followed everything from the Pygame tutorial, but I am getting a very ugly font, and among 25 rectangles, only 1 rectangle shows the text at its center.
How can I fix this?
All of the text is drawn on top of each other. You need to draw the text at different positions. e.g.:
def loop_func():
count = 0
while count < total_length:
data = data_pass[count] # data_pass is an empty list
pygame.draw.rect(window, (255,255,255), (20, 20, width, height))
draw_point(data, (width // 2, height // 2 + count * 20))
If you want to draw the text at different times (counter), you need to change the text by time. See for example How to display dynamically in Pygame?

What is the difference between pygame.Rect() and pygame.draw.rect()?

I was learning to create a simple Pygame window which displays a Rectangle. I watched two different videos on Youtube. One of the Youtuber used Pygame.draw.rect() to create a rectangle whereas other Youtuber used both pygame.Rect() and Pygame.draw.rect(). Both gave same result at the end. So what is the difference between these two codes??
pygame.Rect is a class whose instances represent rectangular areas.
pygame.draw.rect is a function that draws rectangles. One of its arguments is a pygame.Rect instance representing the rectangle to draw.
They are completely different things.
pygame.Rect creates a Rect instance to be passed into pygame.draw.rect. Consider this short snippet:
For anyone else who is reading this, first install pygame by running pip install pygame in your IDE's terminal or your default operating system's terminal.
import pygame
SCREEN = pygame.display.set_mode((300, 300))
while True:
pygame.draw.rect(SCREEN, 'white', (30, 30, 100, 100))
pygame.display.update()
The tuple that we passed in to pygame.draw.rect consists of (x, y, width, height):
x being where our rectangle will sit on the vertical axis
y being where our rectangle will sit on the horizontal axis
width being the width of our rectangle
height being the height of our rectangle
This is how you would use pygame.draw.rect by itself. Behind the scenes, pygame transforms this tuple into a pygame.Rect object. So you are only doing a bit more work when using pygame.Rect. For example:
pygame_rect_object = pygame.Rect(30, 30, 100, 100)
pygame.draw.rect(SCREEN, 'white', pygame_rect_object)
As you can see, creating a pygame.Rect object is the same as passing the tuple. A few advantages are readability, and you can pass it into multiple pygame.draw.rect functions without having to repeat the tuple.
Hope this has helped!!!

Cannot align text with a line drawn on an image

I'm trying to do some image manipulation with the python library Pillow (fork of PIL) and am coming across a weird problem. For some reason, when I try to draw a line and draw some text at the same y coordinate, they're not matching up. The text is a bit below the line, yet I have both graphics starting at the same point. Has anyone had this problem before and/or know how to solve it? Here's the code I'm using:
image = Image.open("../path_to_image/image.jpg")
draw = ImageDraw.Draw(image)
font = ImageFont.truetype("../fonts/Arial Bold.ttf", 180)
draw.line((0,2400, 500,2400), fill="#FFF", width=1)
draw.text((0, 2400), "Test Text", font=font)
image.save(os.path.join(root, "test1.jpg"), "JPEG", quality=100)
return
I get something similar (with sizes 10 times smaller):
This is happening because the (x,y) coordinates given to ImageDraw.text() are the top left corner of the text:
PIL.ImageDraw.Draw.text(xy, text, fill=None, font=None, anchor=None)
Draws the string at the given position.
Parameters:
xy – Top left corner of the text.
text – Text to be drawn.
font – An ImageFont instance.
fill – Color to use for the text.
This is confirmed in the code: the text is turned into a bitmap and then drawn at xy.
For those with a similar problem, I ended up creating a helper function that manually adjusts the font size until font.getsize(text)[1] returns the correctly sized text. Here's a snippet:
def adjust_font_size_to_line_height(font_location, desired_point_size, text):
adjusted_points = 1
while True:
font = ImageFont.truetype(font_location, adjusted_points)
height = font.getsize(text)[1]
if height != desired_point_size:
adjusted_points += 1
else:
break
return adjusted_points

Updating part of a surface in python, or transparent surfaces

I have an application written in python that's basically an etch-a-sketch, you move pixels around with WASD and arrow keys and it leaves a trail. However, I want to add a counter for the amount of pixels on the screen. How do I have the counter update without updating the entire surface and pwning the pixel drawings?
Alternatively, can I make a surface that's completely transparent except for the text so you can see the drawing surface underneath?
To solve this problem, you want to have a separate surface for your Etch-a-Sketch pixels, so that they do not get clobbered when you go to refresh the screen. Unfortunately, with Rigo's scheme, the font will continue to render on top of itself, which will get messy for more than two pixel count changes.
So, here's some sample rendering code:
# Fill background
screen.fill((0xcc, 0xcc, 0xcc))
# Blit Etch-a-Sketch surface (with the drawing)
# etch_surf should be the same size as the screen
screen.blit(etch_surf, (0, 0))
# Render the pixel count
arial = pygame.font.SysFont('Arial', 20)
counter_surf = arial.render(str(pixel_count), True, (0, 0, 0))
screen.blit(counter_surf, (16, 16))
# Refresh entire screen
pygame.display.update()
Now, admittedly, updating the entire screen is rather inefficient. For this, you have two options: only refresh the screen when the drawing changes or track the location of drawing changes and refresh individual locations (see the update documentation). If you choose the second option, you will have to refresh the text and where it was previously; I would recommend having a Sprite manage this.
What you need is pygame.font module
#define a font surface
spamSurface = pygame.font.SysFont('Arial', 20)
#then, in your infinite cycle...
eggsPixels = spamSurface.render(str(pixelsOnScreen), True, (255, 255, 255))
hamDisplay.blit(eggsPixels, (10, 10))
Where spamSurface is a new font surface, eggsPixels is the value that spamSurface will render (display/show) and hamDisplay is your main surface display.

Categories

Resources