I'm currently trying to build an app in python with Tkinter, and I'm trying to use an image as a background. I've been able to do that, but when I add other widgets (like frames and labels), their own background overlaps the first one, and the result is not really pleasant. I've search a bit, but I didn't find a way to avoid this. Is it possible ? This is my code :
import tkinter as tk
from PIL import ImageTk, Image
root = tk.Tk()
root.geometry("1280x720")
root.update()
background_img = Image.open("./background.jpg")
background_img = background_img.resize((root.winfo_width(),root.winfo_height()), Image.ANTIALIAS)
background_tkimg = ImageTk.PhotoImage(background_img)
background_label = tk.Label(root, image=background_tkimg)
background_label.place(x=0, y=0, relwidth=1, relheight=1)
frame = tk.Frame(root)
frame.place(anchor="c", relx=.5, rely=.5)
title_label = tk.Label(frame, text="TITLE")
button1 = tk.Button(frame, text="button 1")
button2 = tk.Button(frame, text="button 2")
button3 = tk.Button(frame, text="button 3")
title_label.grid(row=0, column=1, pady=30)
button1.grid(row=1, column=0, padx=20, pady=10)
button2.grid(row=1, column=1, padx=20, pady=10)
button3.grid(row=1, column=2, padx=20, pady=10)
root.mainloop()
And when I run it, I have this window :

This effect can be achieved by using the Tkinter canvas and placing the widgets using .create_window():
import tkinter as tk
from PIL import ImageTk, Image
root = tk.Tk()
root.geometry("1280x720")
root.update()
background_img = Image.open("./background.jpg")
background_img = background_img.resize((root.winfo_width(),root.winfo_height()), Image.ANTIALIAS)
background_tkimg = ImageTk.PhotoImage(background_img)
canvas = tk.Canvas(root, highlightthickness=0)
canvas.pack(expand = True, fill = "both")
canvas.create_image(0,0, image = background_tkimg, anchor = "nw")
root.update()
canvas_height = canvas.winfo_height()
canvas_width = canvas.winfo_width()
title_label = canvas.create_text((canvas_width//2), (canvas_height//2) - 25, fill = "white", text="TITLE")
button1 = tk.Button(canvas, text="button 1")
button2 = tk.Button(canvas, text="button 2")
button3 = tk.Button(canvas, text="button 3")
canvas.create_window((canvas_width//2) - 75, (canvas_height//2) + 25 , window = button1)
canvas.create_window((canvas_width//2), (canvas_height//2) + 25, window = button2)
canvas.create_window((canvas_width//2) + 75, (canvas_height//2) + 25, window = button3)
root.mainloop()
The label has been replaced with canvas.create_text() for a transparent background. The positioning isn't the same as the original, it's just based off approximate offsets from the centre.
This produces this result:

Unfortunately, the only way to avoid this is to use a Canvas and display all other widgets with help of .create_window and similar methods. Moreover, you won't be able to use pack, place and grid geometry managers. Instead, you need to calculate coordinates from the top left corner of the Canvas and create other objects according to them.
import tkinter as tk
from PIL import ImageTk, Image
W, H = 1280, 720
root = tk.Tk()
root.geometry("{}x{}".format(W, H))
root.resizable(False, False)
root.update()
background_img = Image.open("./background.jpg").resize((W, H), Image.ANTIALIAS)
background_tkimg = ImageTk.PhotoImage(background_img)
canv = tk.Canvas(root)
canv.create_image(0, 0, image=background_tkimg, anchor="nw")
canv.place(x=0, y=0, relwidth=1, relheight=1)
canv.create_text(W / 2, H / 2, fill="white", text="TITLE")
for i in range(1, 4):
canv.create_window(W / 2 - 200 + i * 100, H / 2 + 65, window=tk.Button(canv, text="button {}".format(i)))
root.mainloop()
Note that I have changed the "TITLE" text color (with fill argument) to white, otherwise it is hard to see it on the dark background. Here is a screenshot (with a similar background).

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With