0

I'm trying to set a background image to my tkinter window, however I don't quite know how to resize it so it fits the dimensions of the window. I've looked online, and all the tutorials/answers use pack (to expand and fill), but I can't use pack because I have a bunch of other buttons/labels that all use grid (this is a minimal workable example, my actual script is much bigger with more buttons/larger size). Is there any way to do this using grid?

This is my current setup:

import tkinter as tk
from PIL import ImageTk, Image

root = tk.Tk()
background_image = ImageTk.PhotoImage(Image.open("pretty.jpg"))
l=tk.Label(image=background_image)
l.grid()

tk.Label(root, text="Some File").grid(row=0)
e1 = tk.Entry(root)
e1.grid(row=0, column=1)


tk.mainloop()
samman
  • 559
  • 10
  • 29
  • neither `pack` nor `grid`, or even `place` will resize the image. It is up to you to set the image to an appropriate size. – Bryan Oakley Jun 17 '20 at 13:44
  • If you want the image to appear behind everything, you'd need to give it `rowspan`/`columnspan` options that make it cover every row/column used by other widgets. The way you have it now, the Entry *cannot* overlap the image, because they are in different columns. – jasonharper Jun 17 '20 at 13:48
  • You can use `place()`. – acw1668 Jun 17 '20 at 13:51
  • Does this answer your question? [what-does-weight-do-in-tkinter](https://stackoverflow.com/questions/45847313) – stovfl Jun 17 '20 at 13:51
  • @jasonharper this won't work if I expand my tkinter window (i.e. click the expand button), I'd like the image to "fit"/"fill" the window dimensions, even if they change – samman Jun 17 '20 at 15:03
  • @acw1668 I've tried using at place with relheight and relwidth so it fits the window dimensions, but this doesn't. – samman Jun 17 '20 at 15:04
  • @stovfl I've never used weight, but from that post, it appears it changes the "size" of a particular column (in contrast to column_span which only changes a singular objects size, this changes the size of everything within that column). To this end I've tried to move the image to a different column, and then use weight on that column, but it hasn't worked: l.grid(column=3) root.grid_columnconfigure(3, weight=1), but this didn't change the image size. – samman Jun 17 '20 at 15:07
  • ***but this didn't change the image size***: See the first comment .... It resizes the `Label` widget. Relevant [`[tkinter] background image resize`](https://stackoverflow.com/search?q=is%3Aanswer+%5Btkinter%5D+background+image+resize) – stovfl Jun 17 '20 at 15:10
  • @stovfl I apologize, I'm relatively new to all this. But isn't the label widget the image? Thus resizing the label widget should expand/minimize the picture to fit it? – samman Jun 17 '20 at 15:14
  • ***isn't the label widget the image?***: No, it's the container holding a image of a given size. The `Label` can dynamic resized, but the image doesn't. This [how-to-resize-an-image-to-fit-the-label-size-python](https://stackoverflow.com/questions/36959396) may fit your needs – stovfl Jun 17 '20 at 15:17
  • How about `Image.open("pretty.jpg").resize((w,h))` or `Image.open("pretty.jpg").crop((w,h))`? If you need to get the window size, use `width,height = root.winfo_xy()` or, in `Label` case, `width,height = label.winfo_xy()`. – rizerphe Jun 17 '20 at 15:18

1 Answers1

4

You can use place(x=0, y=0, relwidth=1, relheight=1) to lay out the background image label. In order to fit the image to the window, you need to resize the image when the label is resized.

Below is an example based on your code:

import tkinter as tk
from PIL import Image, ImageTk

def on_resize(event):
    # resize the background image to the size of label
    image = bgimg.resize((event.width, event.height), Image.ANTIALIAS)
    # update the image of the label
    l.image = ImageTk.PhotoImage(image)
    l.config(image=l.image)

root = tk.Tk()
root.geometry('800x600')

bgimg = Image.open('pretty.jpg') # load the background image
l = tk.Label(root)
l.place(x=0, y=0, relwidth=1, relheight=1) # make label l to fit the parent window always
l.bind('<Configure>', on_resize) # on_resize will be executed whenever label l is resized

tk.Label(root, text='Some File').grid(row=0)
e1 = tk.Entry(root)
e1.grid(row=0, column=1)

root.mainloop()
acw1668
  • 40,144
  • 5
  • 22
  • 34
  • Thank you this worked! I just want to make sure I understand what's going on here. The fun on_resize takes the image, and resizes it when the label size changes. It changes the size to the label size to be exact. l'm a bit confused as to what l.config is doing. After that, the image is uploaded as usual, l.place simply fits it to the window, and l.bind then says when the label size changes, changes the size of image (via on_resize). Do I understand that correctly? – samman Jun 17 '20 at 21:10
  • `bind()` is used to register callback which will be executed whenever some condition is happened. `` is used for geometry change. The `l.place(...)` is used to make the label fit the parent window, therefore whenever the window is resized, the label is resized too and so the `on_resize()` function will be executed. `l.config()` is used to set some attributes, e.g. text, image, foreground color, etc. – acw1668 Jun 18 '20 at 00:44