Home > other >  How to center an image in tkinter with PIL
How to center an image in tkinter with PIL

Time:05-09

I want to center an image in tkinter but I cant do it here is my code

def newsetup(filelocation):
    global width, height
    
    for widgets in root.winfo_children():
        widgets.destroy()

    stage = Canvas(root, width = 1000, height = 700, highlightbackground = 'red', highlightthickness = 2)
    stage.pack()

    imgtk = ImageTk.PhotoImage(Image.open(filelocation)) 
    stage.create_image(stage.winfo_width()   2, stage.winfo_height()   2, image = imgtk, anchor = CENTER)
    stage.image = imgtk

CodePudding user response:

if you want to center on canvas then you need

stage.winfo_width()/2, stage.winfo_height()/2

(even without anchor= which as default has value center)

But if you put image before it runs mainloop() then stage.winfo_width() stage.winfo_height() gives 0,0 instead of expected width, height (because mainloop creates window and it sets all sizes for widgets) and it may need root.update() to run mainloop once and it will calculate all sizes.

import tkinter as tk
from PIL import ImageTk, Image

root = tk.Tk()

stage = tk.Canvas(root, width=1000, height=700)
stage.pack()

root.update()  # force `mainloop()` to calculate current `width`, `height` for canvas
               # and later `stage.winfo_width()` `stage.winfo_height()` will get correct values instead `0`
    
#imgtk = ImageTk.PhotoImage(Image.open('lenna.png'))
imgtk = ImageTk.PhotoImage(file='lenna.png')

stage.create_image((stage.winfo_width()/2, stage.winfo_height()/2), image=imgtk, anchor='center')
stage.image = imgtk

root.mainloop()

Result:

enter image description here


Image Lenna from Wikipedia.


EDIT:

If you want to keep it centered when you resize window then you can bind event <Configure> to canvas and it will execute assigned function - and it can move image.

But it needs image ID which you can get when you create image

img_id = stage.create_image(...)

Because <Configure> is executed when it creates window so code doesn't need root.update() because on_resize() will set correct position at start.

import tkinter as tk
from PIL import ImageTk, Image

# --- functions ---

def on_resize(event):
    # it respects anchor
    x = event.width/2  
    y = event.height/2
    stage.coords(img_id, x, y)  
    
    # it DOESN'T respects anchor so you have to add offset
    #x = (event.width - imgtk.width())/2  
    #y = (event.height - imgtk.height())/2
    #stage.moveto(img_id, x, y)  # doesn't respect anchor

    #stage.itemconfigure(img_id, ...)

# --- main ---

root = tk.Tk()

stage = tk.Canvas(root, width=1000, height=700)
stage.pack(fill='both', expand=True)

#root.update()  # force `mainloop()` to calculate current `width`, `height` for canvas
               # and later `stage.winfo_width()` `stage.winfo_height()` will get correct values instead `0`
    
#imgtk = ImageTk.PhotoImage(Image.open('lenna.png'))
imgtk = ImageTk.PhotoImage(file='lenna.png')

img_id = stage.create_image((stage.winfo_width()/2, stage.winfo_height()/2), image=imgtk, anchor='center')
stage.image = imgtk

stage.bind('<Configure>', on_resize)  # run function when Canvas change size

root.mainloop()
  • Related