Tkinter: Overlaying a label on top of a background image - python

I'm trying to create my first GUI, using Python and Tkinter. I want to have a background image that resizes accordingly with the window size, along with two labels on top of the background, both placed about midway on the window. The two labels are "Full Name" and "Education", as shown in my code below.
Currently, I'm using the pack() method, and I've been using the window resizing code from here.
My question is: How do I get the labels to overlap the background image (also a label in my code)? With my current code, the background image seems to be on top of the frame and labels.
Attached is a picture of the output/GUI I'm looking for, except I want my image to be in the background.
GUI
#Resize using label
from tkinter import *
from tkinter import ttk
from PIL import Image, ImageTk
root = Tk()
root.title("Title")
root.geometry('600x600')
def resize_image(event):
new_width = event.width
new_height = event.height
image = copy_of_image.resize((new_width, new_height))
photo = ImageTk.PhotoImage(image)
label.config(image = photo)
label.image = photo #avoid garbage collection
#Background image
image = Image.open("filepath.jpg")
copy_of_image = image.copy()
photo = ImageTk.PhotoImage(image)
label = Label(root, image = photo)
label.bind('<Configure>', resize_image)
label.place(x=0, y=0, relwidth=1, relheight=1)
label.pack(fill=BOTH, expand = YES)
label.lower()
frame = Frame(root, width=600, height=600, relief='raised', borderwidth=2)
frame.pack(fill="both", expand=True)
frame.pack_propagate(False)
#Top Frame
top_frame = Frame(frame,width=600, height=350)
top_frame.pack(side = TOP)
#Various Labels
Label(frame, text = 'Full Name', width = 8).pack()
Label(frame, text = 'Education', width = 8).pack()
root.mainloop()

Some rearrangement is in order. Your large frame is sitting atop the background image, covering it completely. So, let's make the background Label part of frame, not root. You should probably either place() or pack() but not both. To get the other labels to the center, I created a centered frame and packed them in to it. There are probably other ways to do all of this:
from tkinter import *
from PIL import Image, ImageTk
def resize_image(event):
new_width = event.width
new_height = event.height
image = copy_of_image.resize((new_width, new_height))
photo = ImageTk.PhotoImage(image)
label.config(image=photo)
label.image = photo # avoid garbage collection
root = Tk()
root.title("Title")
root.geometry('600x600')
frame = Frame(root, relief='raised', borderwidth=2)
frame.pack(fill=BOTH, expand=YES)
frame.pack_propagate(False)
copy_of_image = Image.open("filepath.jpg")
photo = ImageTk.PhotoImage(copy_of_image)
label = Label(frame, image=photo)
label.place(x=0, y=0, relwidth=1, relheight=1)
label.bind('<Configure>', resize_image)
center_frame = Frame(frame, relief='raised', borderwidth=2)
center_frame.place(relx=0.5, rely=0.5, anchor=CENTER)
Label(center_frame, text='Full Name', width=8).pack()
Label(center_frame, text='Education', width=8).pack()
root.mainloop()

Related

Tkinter images and geometry creation

I've tried to do a star fractal drawing a star using tkinter and putting an image as a background.
from tkinter import *
from PIL import ImageTk, Image
import tkinter as tk
app = Tk()
app.title("Welcome")
img =Image.open('C:\\Users\\Stefa\\Downloads\\galaxy.jpeg')
bg = ImageTk.PhotoImage(img)
canvas_width=800
canvas_height=800
master = tk.Tk()
label = Label(app, image=bg)
label.place(x = 0,y = 0)
label2 = Label(app, text = "WELCOME TO OUR GALAXY",
font=("Times New Roman", 24))
label2.pack(pady = 50)
app.geometry(f"{canvas_width}x{canvas_height}")
can_widgt=Canvas(app, width=canvas_width, height= canvas_height)
can_widgt.pack()
points=[200,20,80,396,380,156,20,156,320,396]
can_widgt.create_polygon(points, outline='red',fill='cyan', width=6)
app.mainloop()
That's the code
However when i run it i want the star to be upon the background image. Any solutions for this ? Thanks
You need to create the image as a canvas object rather than as a label.
For example, this add the image to the top-left corner of the canvas, with the drawing on top of it:
can_widgt.create_image(0, 0, anchor="nw", image=bg)

How can I add Unscrollable Image to a frame/Canvas?

In Tkinter Canvas how can I place a image on a canvas/Frame that has Scrollbar attached to it. But on Scrolling the scrollbar the Image shouldn't scroll, Rather the other contents like(Label) should move while scrolling making image unscrollable and below label.
I do it by using new yview function for scrollbar, update position of background image as the scrollbar.
from PIL import Image
from tkinter import Tk, Label, Frame, Canvas, Scrollbar, PhotoImage
def yview(action, fraction):
canvas.yview(action, fraction)
x, y = canvas.coords(bg)
dy = canvas.canvasy(0)-y
canvas.move(bg, 0, dy)
image_file = "d:/chess.png"
width, height = Image.open(image_file).size
root = Tk()
vscrollbar = Scrollbar(root, orient='vertical')
vscrollbar.pack(side='right', fill='y', expand=0)
canvas = Canvas(root, width=width, height=height, bg='green', yscrollcommand=vscrollbar.set)
canvas.pack(side='left', padx=0, pady=0, ipadx=0, ipady=0)
vscrollbar.configure(command=yview)
image = PhotoImage(file=image_file)
bg = canvas.create_image(0, 0, image=image, anchor='nw')
# ======================== Block ======================================
frame = Frame(canvas)
frame_id = canvas.create_window(width//2, 0, window=frame, anchor="n")
for i in range(30):
Label(frame, text=f'Label {i+1:0>2d}', padx=5, pady=5).pack()
# ==================================================================
canvas.update()
canvas.configure(scrollregion=canvas.bbox('all'))
root.mainloop()
[Update] frame used as container of labels will mask background image, to avoid this, need to put each widget under canvas directly.
Code for Block replaced by
label_ids = []
for i in range(30):
label = Label(canvas, text=f'Label {i+1:0>2d}', padx=5, pady=5)
h = label.winfo_reqheight()
label_id = canvas.create_window(width//2, int(i*(h*1.5)), window=label, anchor="n")

Is it possible to give slideDown transition on Image in Tkinter?

Just like how we give effects on image in Jquery using the code
$('.img').slideDown('fast', 'linear', function() {});
Is there any way to give slideDown effect on canvas image in tkinter ?
This is my code.
from tkinter import *
from PIL import Image, ImageTk
root = Tk()
frame = Frame(root)
frame.pack()
canvas = Canvas(frame, width=300, height=300, bd=0, highlightthickness=0, relief='ridge')
canvas.pack()
background = PhotoImage(file="background.png")
canvas.create_image(300,300,image=background)
my_pic = PhotoImage(file="start000-befored.png") #and on this image, I want to give slidedown effect.
canvas.create_image(50,50,image=my_pic, anchor=NW)
root.mainloop()

How do I make my Label Tkinter element display?

Currently, I am creating a text adventure game. Now to make it a tiny bit better than a lot of them which use the python console, I am using Tkinter to make a GUI. Only it displays my background image for the start screen, but not the text I put there! Please help!
# writes the title as text in the window
titleFont = tkFont.Font(family = "Comic Sans MS", size = 20)
titleText = tkinter.Label(app, text="Gods of This World", font=titleFont)
titleText.pack()
# sets the background image to the games 3 colors (Red, Green, Grey)
C = tkinter.Canvas(app, height=300, width=250)
filename = tkinter.PhotoImage(file = "C:/Users/" + getpass.getuser() + "/Desktop/Gods of This World/net/godsofthisworld/ui/images/backgroundimage.png")
background_label = tkinter.Label(app, image=filename)
background_label.place(x=0, y=0, relwidth=1, relheight=1)
C.pack()
You put image after text - and you use .place(x=0, y=0, relwidth=1, relheight=1) - so text is hidden behind image.
Put it in different order - first image, next text.
import tkinter as tk
app = tk.Tk()
# first image
photo = tk.PhotoImage(file="image.png")
background_label = tk.Label(app, image=photo)
background_label.place(x=0, y=0, relwidth=1, relheight=1)
# next text
titleText = tk.Label(app, text="Gods of This World")
titleText.pack()
app.mainloop()
BTW: label with text will have gray background - and you can't remove it. If you want text without background then use Canvas and canvas.create_image(), canvas.create_text() - without pack() and place()
import tkinter as tk
WIDTH = 800
HEIGHT = 600
app = tk.Tk()
canvas = tk.Canvas(width=WIDTH, height=HEIGHT)
canvas.pack()
photo = tk.PhotoImage(file="image.png")
canvas.create_image((WIDTH/2, HEIGHT/2), image=photo) #, anchor='center')
canvas.create_text((WIDTH/2, HEIGHT/2), text="Gods of This World") #, anchor='center')
app.mainloop()

tkinter background image in Frame

I want to put a background image in a Frame, this is the code that I'm trying to run without success.
import tkinter as tk
from tkinter import *
root = tk.Tk()
F1 = Frame(root)
F1.grid(row=0)
photo = PhotoImage(file="sfondo.png")
label = Label(F1, image=photo)
label.image = photo
label.place(x=0, y=0)
b = tk.Button(label, text="Start")
b.grid(row=8, column=8)
root.mainloop()
If I run the code as this, only a little point in the top left corner is displayed (the frame without nothing in, even if I placed the label inside of it). If I replace the label parent with root, it displays the button with a little part of the image as backgound (only the perimeter of the button is colored for a few pixels). However what I want is a full displayed background image in the frame where I can put the widgets that I want.
I tried to with the place method as this and PIL module
import tkinter as tk
from tkinter import *
from PIL import Image, ImageTk
root = tk.Tk()
F1 = Frame(root)
F1.grid(row=0)
image = Image.open("sfondo.png")
render = ImageTk.PhotoImage(image)
img = tk.Label(F1, image=render)
img.image = render
img.place(x=0, y=40)
b = tk.Button(img, text="Start")
b.grid(row=8, column=8)
root.mainloop()
Here more or less I'm having the same problems, if I set the parent of the label to root, the button is displayed with the perimeter coloured.
If I set the parent to F1 nothing happens and in both cases if I set the parent as root and remove the button, the image is fully displayed.
But what I want is that the image is fully displayed in the frame and after diplay on the background image the widgets.
You could put an image on a Canvas, and then place a Button on that by putting it inside a Canvas window object which can hold any Tkinter widget.
Additional widgets can be added in a similar fashion, each inside its own Canvas window object (since they can hold only a single widget each). You can workaround that limitation by placing a Frame widget in the Canvas window, and then putting other widgets inside it.
Here's an example showing how to display a single Button:
from PIL import Image, ImageTk
import tkinter as tk
IMAGE_PATH = 'sfondo.png'
WIDTH, HEIGTH = 200, 200
root = tk.Tk()
root.geometry('{}x{}'.format(WIDTH, HEIGHT))
canvas = tk.Canvas(root, width=WIDTH, height=HEIGTH)
canvas.pack()
img = ImageTk.PhotoImage(Image.open(IMAGE_PATH).resize((WIDTH, HEIGTH), Image.ANTIALIAS))
canvas.background = img # Keep a reference in case this code is put in a function.
bg = canvas.create_image(0, 0, anchor=tk.NW, image=img)
# Put a tkinter widget on the canvas.
button = tk.Button(root, text="Start")
button_window = canvas.create_window(10, 10, anchor=tk.NW, window=button)
root.mainloop()
Screenshot:
Edit
While I don't know of a way to do it in Frame instead of a Canvas, you could derive your own Frame subclass to make adding multiple widgets easier. Here's what I mean:
from PIL import Image, ImageTk
import tkinter as tk
class BkgrFrame(tk.Frame):
def __init__(self, parent, file_path, width, height):
super(BkgrFrame, self).__init__(parent, borderwidth=0, highlightthickness=0)
self.canvas = tk.Canvas(self, width=width, height=height)
self.canvas.pack()
pil_img = Image.open(file_path)
self.img = ImageTk.PhotoImage(pil_img.resize((width, height), Image.ANTIALIAS))
self.bg = self.canvas.create_image(0, 0, anchor=tk.NW, image=self.img)
def add(self, widget, x, y):
canvas_window = self.canvas.create_window(x, y, anchor=tk.NW, window=widget)
return widget
if __name__ == '__main__':
IMAGE_PATH = 'sfondo.png'
WIDTH, HEIGTH = 350, 200
root = tk.Tk()
root.geometry('{}x{}'.format(WIDTH, HEIGTH))
bkrgframe = BkgrFrame(root, IMAGE_PATH, WIDTH, HEIGTH)
bkrgframe.pack()
# Put some tkinter widgets in the BkgrFrame.
button1 = bkrgframe.add(tk.Button(root, text="Start"), 10, 10)
button2 = bkrgframe.add(tk.Button(root, text="Continue"), 50, 10)
root.mainloop()
Result:
Update
It recently dawned on me that there actually is a simpler way to do this than creating a custom Frame subclass as shown in my previous edit above. The trick is to place() a Label with image on it in the center of the parent Frame — you are then free to use other geometry managers like pack() and grid() as you normally would — as illustrated in the sample code below. Not only is it less complicated, it's also a more "natural" way of adding widgets than needing to call a non-standard method such as add().
from PIL import Image, ImageTk
import tkinter as tk
IMAGE_PATH = 'sfondo.png'
WIDTH, HEIGHT = 250, 150
root = tk.Tk()
root.geometry('{}x{}'.format(WIDTH, HEIGHT))
# Display image on a Label widget.
img = ImageTk.PhotoImage(Image.open(IMAGE_PATH).resize((WIDTH, HEIGHT), Image.ANTIALIAS))
lbl = tk.Label(root, image=img)
lbl.img = img # Keep a reference in case this code put is in a function.
lbl.place(relx=0.5, rely=0.5, anchor='center') # Place label in center of parent.
# Add other tkinter widgets.
button = tk.Button(root, text="Start")
button.grid(row=0, column=0)
button = tk.Button(root, text="Continue")
button.grid(row=0, column=1, padx=10)
root.mainloop()
Result#2
P.S. You can download a copy of the sfondo.png background image from here.

Categories

Resources