Gravity seemed like what I wanted but it does not let me change the x offset.
bg.caption(f"{xp} / {req_xp}", left=200, top=165, font=montserrat_bold, gravity='north_east')
Correctly offsets in the y direction but no matter what I put for left it remains glued to the right. Is this a bug with wand? I saw several examples of pure imagemagick where alignment seemed possible.
Captions are created by building a new bounding box (width x height), and renders the text to fit within the box -- while respecting the gravity parameter. After the text has been rendered, the bonding box is composited at the left x top coordinates of the image.
[...] it remains glued to the right. Is this a bug with wand?
With gravity set to "north_east" & width undefined, the text will remain "glued to the right".
Try the following ...
bg.caption(f"{xp} / {req_xp}",
left=200,
top=165,
width=100,
height=50,
font=montserrat_bold,
gravity='north_east')
Adjust the width= & height= parameter values to respect the pointsize of montserrat_bold variable.
Related
I was wondering how to measure the width of a text in tkinter canvas. I have a text displayed somewhere:
myCanvas.create_text(400,410, text="This is my text", tags="my_tag")
and at some point there is a shape (polygon line) that may overlap when the text gets longer (text will be changed with .itemconfigure()). In this case I wanted to break the text in lines, which works well with the width option.
To figure out if objects overlap there are a couple of possible methods: find_overlapping() or find_enclosed(), however, they do require 4 coordinates and myCanvas.coords("my_tag") only returns 2 coordinates. How could I figure out the other x2, y2?
An alternative was to use find_closest(), however, there are a bunch of shapes closer than the overlapping one, so that is not accurate.
Another alternative was that I could figure out the intersecting coordinate and then just take the distance to the x coordinate of the text and double that as a width (since text gets drawn from the center), for example:
intersection point at (350,405) => width = 2 * (400-350)
However, since the shape is a line (part of a polygon) that goes diagonal, I'm not sure how get the intersection point other than having a loop that creates a line that slowly increases till it overlaps with an object, for example:
text_center = (400,410)
start_x = text_center[0]
start_y = text_center[1]
extender = 1
while(myCanvas.find_overlapping(start_x, start_y, start_x+entender, start_y == ())
myCanvas.delete("mytestline")
extender += 1
myCanvas.create_line(start_x, start_y, start_x+extender, start_y, tags="mytestline")
overlapping_point = (start_x+extender, start_y)
Is there an easier way?
The bbox method will return the bounding box of any item or group of items on the canvas. The bounding box is the smallest rectangle that contains the elements, give or take a pixel or two. The returned value is a tuple of the two coordinates.
The following example creates a text item, gets and displays the bounding box, and also uses the coordinates to draw a rectangle around the text so you can visually see that the numbers are correct.
import tkinter as tk
root = tk.Tk()
myCanvas = tk.Canvas(root)
myCanvas.pack(fill="both", expand=True)
item_id = myCanvas.create_text(100,50, text="This is my text", tags="my_tag")
bbox = myCanvas.bbox(item_id)
myCanvas.create_rectangle(bbox, outline="red")
myCanvas.create_text(100, 70, text=f"bbox: {bbox}")
root.mainloop()
I am making a scene where there is a thumbs-up image that is supposed to get bigger on mouse hover, and shrink back to normal size when the mouse is no longer hovering.
This is how I make the thumbs-up image:
thumbs_up_image = pygame.image.load("./plz_like.png")
thumbs_up_rect = thumbs_up_image.get_rect(topleft=(screen.get_width() // 2 - thumbs_up_image.get_width() + 75,
screen.get_height() // 2 + thumbs_up_image.get_height() - 225))
And this is how I make it get bigger:
if thumbs_up_rect.collidepoint(pygame.mouse.get_pos()):
thumbs_up_image = pygame.transform.scale(thumbs_up_image,
[n + 50 for n in thumbs_up_image.get_size()])
thumbs_up_rect = thumbs_up_image.get_rect()
This is how the image is blited:
screen.blit(thumbs_up_image, thumbs_up_rect)
The problem is that when I hover on the thumbs-up image, it first goes to the top-left corner of the screen. Then, when I hover on it again, it gets super big and pixelated.
What am I doing wrong?
I managed to figure it out by myself.
This is how I do it:
First, I prepared a bigger version of the image and it's rect: (as shown below)
big_thumbs_image = pygame.transform.scale(thumbs_up_image, [i + 50 for i in thumbs_up_image.get_size()])
big_thumbs_image_rect = thumbs_up_image.get_rect(
topleft=(screen.get_width() // 2 - thumbs_up_image.get_width() + 55,
screen.get_height() // 2 + thumbs_up_image.get_height() - 250))
Then, when the small image's rect collides with the mouse, blit the bigger image:
if thumbs_up_rect.collidepoint(pygame.mouse.get_pos()):
screen.blit(big_thumbs_image, big_thumbs_image_rect)
You are not showing the code that actually renders the image to the screen.; But basically: you are not saving the original size - at each hover event it will grow and grow (and it will grow once per frame, if that code is run in the mainloop).
You need a variable to hold the original image, one to tell your code the image has already been resized, and an else clause on this if to restore the original image: pygame won't do that for you.
Also, when you use the get_rect for the image, its top-left position will always be "0, 0" - you have to translate this top-left corner to a suitable coordinate- getting the rectangle center of the original sprite (wherever the data of its location on the screen is kept), and setting the same center on the new rect should work.
And finally, prefer "rotozoom" than "scale" - Pygame documentation is clear that the second method uses better algorithms for scaling.
Try using this pygame function:
pygame.transform.rotozoom(Surface, angle, scale)
I also had some issues with pixilation in a game but it seemed to work with this.
I'm trying to position 1 symbol in the top left corner of the given bounding box.
draw = ImageDraw.Draw(img)
font = ImageFont.truetype('LiberationSans-Regular.ttf', 150)
draw.text((x0, y0), "€", "green", font=font)
But when I place text, for example at (0, 0) of the box, it appears with some padding at the top. Also it seems padding size depends on font size.
Is there a way to calculate size of this padding? And maybe move it on that exact amount of pixels upwards.
Basically top pixel of the given symbol must be at y0 of the bounding box, regardless of font and font size.
I understand the very beginning which creates the window size, but I see people put +x+x after the initial 400x300 or whatever size. I've looked all over for an answer but can't seem to find one.
width x height + x position + y position, positions relative to the top left corner of the screen in pixels
Edit:
Here's a brief summary of the function from tcl.tk, written up much more concisely than I could hope to achieve.
root.geometry("%dx%d+0+0" % (w, h))
its just where do you want the pixel from, setting the top and left corner of the screen
you can also see the link http://effbot.org/tkinterbook/place.htm
What would be the best way to use negative coordinates in pygame?
At the moment I have a surface that is 1.5 times the original surface then everything that needs to be drawn is shifted up by a certain amount (to ensure the negative coordinates become positive) and drawn.
Is there an easier/alternate way of doing this?
A simple solution is to write a linear mapping function from world coordinates to pygame screen coordinates
def coord(x,y):
"Convert world coordinates to pixel coordinates."
return 320+170*x, 400-170*y
and use it when drawing all world objects. Have a look here for a complete example.
There is no way to move the origin of a surface from 0,0.
Implement your own drawing class which transforms all the coordinates passed in into the space of the surface.
If it's similar to an RPG map situation, where you have world coordinates and screen coordinates:
use a function that translates world to local, and vice versa.
But I wasn't sure I'd you were looking for Rect's properties?
rect.bottomright = (width, height) # bottom right at window corner
If you want to use center coordinates to blit, vs top left being (0,0)
ship.rect.center = (20, 30) # don't need to translate by adding w/2 to topleft
See also: Rect.move_ip()