How to make a tkinter Label background transparent? - python

I have a window with a label as my frame. I did this because i wanted an image in the background. But now im having trouble with the other labels i have used. The other labels i have used to actually labeled things dont have a transparent background. Is there a way to make the background of these labels transparent?
import Tkinter as tk
root = tk.Tk()
root.title('background image')
image1 = Tk.PhotoImage(file='image_name.gif')
# get the image size
w = image1.width()
h = image1.height()
# make the root window the size of the image
root.geometry("%dx%d" % (w, h))
# root has no image argument, so use a label as a panel
panel1 = tk.Label(root, image=image1)
panel1.pack(side='top', fill='both', expand='yes')
# put a button/label on the image panel to test it
label1 = tk.Label(panel1, text='here i am')
label1.pack(side=Top)
button2 = tk.Button(panel1, text='button2')
button2.pack(side='top')
# start the event loop
root.mainloop()

i think it can help, all black will be transparent
root.wm_attributes('-transparentcolor','black')

It is not supported with transparent backgrounds in Tk.

If you are working with images and putting text onto them, the most convenient way is - I think - utilizing Canvas widget.
tkinter Canvas widget has methods as .create_image(x, y, image=image, options) and .create_text(x, y, text="Some text", options).

use this :
from tkinter import *
main=Tk()
photo=PhotoImage(file='test.png')
Label(main,image=photo,bg='grey').pack()
#your other label or button or ...
main.wm_attributes("-transparentcolor", 'grey')
main.mainloop()
this work if use bg='grey' you can change it in line 7
good luck :)

Related

Python: auto slideshow with PIL/TkInter with no saving images

I´m designing a slideshow with no user intervention, where:
a. Every image is generated by the Python script itself
b. There´s no file saving, for performance reasons
c. Every image is shown in fullscreen for a certain time
d. It´s a loop that´s supposed to never end. There´s always going to be an image to show
So far, by adapting code found in a few pages, I have it running. But every image is shown for X time and then the desktop background appears for a second or so.
I´d like to have a smooth switching from one file to next, such as FEH does. As a matter of fact, I´m trying to replace FEH because I need finer control of the display of each file (for instance, changing the time it appears on screen).
Here´s my code:
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
from PIL import ImageTk
import tkinter
def show_center(pil_image, msDelay):
root = tkinter.Tk()
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.overrideredirect(1)
root.geometry("%dx%d+0+0" % (w, h))
root.focus_set()
root.attributes("-topmost", True)
canvas = tkinter.Canvas(root, width=w, height=h, highlightthickness=0)
canvas.pack()
canvas.configure(background='black')
image = ImageTk.PhotoImage(pil_image)
imagesprite = canvas.create_image(w / 2, h / 2, image=image)
root.after(msDelay, root.destroy)
root.mainloop()
### script body
while True:
# loads common background image
img = Image.open(baseImage)
draw = ImageDraw.Draw(img)
# here: image customization
draw.rectangle(....)
draw.text(....)
img.paste(....)
# shows this file
thisDelay = some Number Calculation
show_center(img, thisDelay)
Any ideas on how to avoid the desktop appearing between images? This will run in a headless Raspberry. I´m using Python3 on Raspbian.
Thanks in advance!
You can use after() instead of the while loop and simply use Label instead of Canvas:
import tkinter as tk
from PIL import Image, ImageTk, ImageDraw, ImageFont
import time
import random
def update_image():
# sample drawing
image = base_image.copy()
draw = ImageDraw.Draw(image)
draw.rectangle((100, 100, 500, 400), outline=random.choice(('red', 'green', 'blue', 'magenta', 'gold', 'orange')))
draw.text((120, 120), f"""{time.strftime("%F %T")}""")
# update image
tkimg = ImageTk.PhotoImage(image)
label.config(image=tkimg)
label.image = tkimg # save a reference to avoid garbage collected
ms_delay = random.randint(1000, 9000) # sample delay calculation
root.after(ms_delay, update_image)
root = tk.Tk()
root.attributes("-fullscreen", 1, "-topmost", 1)
base_image = Image.open("/path/to/base/image")
# label for showing image
label = tk.Label(root, bg="black")
label.pack(fill="both", expand=1)
update_image() # start the slide show
root.mainloop()
Well, it´s working quite well.
The solution required a bit of logic (maybe it makes sense not to destroy the object for every image) and a bit of good old trial & error.
The changes were:
Init the canvas only once, use global vars to make it persistent
For every image, call the display function and keep calling root.update() until the required timeout is reached
So, the prior function gets divided, and it looks like:
global canvas, root
global w, h
def init_image():
global canvas, root
global w, h
root = tkinter.Tk()
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.overrideredirect(1)
root.geometry("%dx%d+0+0" % (w, h))
root.focus_set()
root.attributes("-topmost", True)
canvas = tkinter.Canvas(root, width=w, height=h, highlightthickness=0)
canvas.pack()
canvas.configure(background='black')
return
def show_center(pil_image, msDelay):
global canvas, root
global w, h
image = ImageTk.PhotoImage(pil_image)
imagesprite = canvas.create_image(w / 2, h / 2, image=image)
inicio = int(time.time() * 1000)
while 1:
root.update()
if (int(time.time() * 1000) - inicio) > msDelay:
break
return
Function init_image() is called once at beginning, and function show_center() is called for every image as the original post.
I hope this can be useful to anybody trying to accomplish the same.

Tkinter recursive behavior with '<Configure>' callback

I try to have a tkinter.Frame that have a full screen image and some buttons underneath it
WIDTH, HEIGHT = 800, 600
root = Tk()
mainframe = Frame(root, padding="3 3 12 12")
mainframe.pack(fill=BOTH, expand=True)
infovariable = StringVar()
infovariable_label = Label(mainframe, textvariable=infovariable, anchor=S)
infovariable_label.pack(fill=X, side=TOP)
label = Label(mainframe)
label.pack(fill=BOTH, expand=True)
image_base = Image.open('hello.jpg')
# setting the photo
image = (image_base
.resize(2500, 1000)
.crop(0, 0, WIDTH,HEIGHT))
label.configure(image=photo)
When I do a window resize, I want my photo to be the same dimensions (width/height), if I do that:
def onResize(event):
global WIDTH, HEIGHT
WIDTH = event.width
HEIGHT = max(0, event.height - 50)
# setting the photo
image = (image_base
.resize(2500, 1000)
.crop(0, 0, WIDTH,HEIGHT))
root.bind('<Configure>', onResize)
The resize, makes the image change size, then call the resize again, having a window that infinitely resizes.
I have the same problem as this thread:
odd behavior with '<Configure>' callback
When you bind to the root window, that binding applies to every child of the root window, too, due to how tkinter uses binding tags.
Part of the solution is to change your onResize to only change the size of the image if the event.widget represents the root window. There may be other problems, but that's the first.
You also need to make sure you account for borders. If you make the image the same size of the window, but the label has a one pixel border, that will cause the label to grow, which will cause the root window to grow, which will start the process all over again.
Another answer related to bind tags is here: https://stackoverflow.com/a/2472992/7432

Tkinter: how to draw an image on a canvas with background

I am trying to use tkingter to make a card game.
set a table image as background of the canvas.
draw cards on top of the table background. This will be triggered by clicking a button (not shown here)
The problem is I can't create card image on top of table background. what's the right way to do it? do i need to create another canvas for card, in stead of directly drawing on table background? I feel there is something fundamental that i am missing here.
from tkinter import *
from PIL import Image, ImageTk
# globals
table_dir = "C:/Python36/resourse/table.png"
card_dir = "C:/Python36/resourse/card.jpg"
#CREATE APP
root = Tk()
#LOAD IMAGES
table_PIL = Image.open(table_dir)
table_image = ImageTk.PhotoImage(table_PIL)
card_PIL = Image.open(card_dir)
card_image = ImageTk.PhotoImage(card_PIL)
#make canvas and set background image with a label
canv = Canvas(root, width=table_PIL.width, height=table_PIL.height, background="white")
background_label = Label(canv, image = table_image)
background_label.place(x=0, y=0, relwidth=1, relheight=1)
canv.grid(row=0, column=0)
#trying to create card image on top of background table, not working
canv.create_image(200, 100, image=card_image)
root.mainloop()
Don't use a label for the background. Use canv.create_image(...) to create the background, just like you do for creating cards.

Tkinter - Button Image Transparent Background

I have worked out how to have an image for a button, thats positioned on top of a label (I think I maybe doing it the long-winded way because I can't install PIL on my Mac for some reason). Anyhow, it works as it should to a certain degree - the problem I have is it's adding white space either side, and then the image itself is not displaying its transparent background.
The code I am using is as follows:
from tkinter import *
#from PIL import Image
root = Tk()
#Removes the title bar and places over mac top bar
root.tk.call("::tk::unsupported::MacWindowStyle", "style", root._w, "plain", "none")
# Makes the app full screen
#root.wm_attributes('-fullscreen', 1)
root.geometry('{}x{}'.format(480, 320))
#root.attributes('-topmost', True)
def quitApp():
# mlabel = Label (root, text = 'Close').pack()
root.destroy()
background_img = PhotoImage(file="images/bg.gif")
scanBtn_img = PhotoImage(file="images/scanBtn.gif")
background = Label(root,
compound = CENTER,
quitButton = Button(image=scanBtn_img, command = quitApp).pack(),
image = background_img).pack(side="right")
background.image = background_img # keep a reference!
root.mainloop()
From what I understand tkinter natively supports transparency on images like GIF.
I chopped up your code a little but it does work for me. Maybe there is a problem with how you have set up your code. Your label also has a button in it. I don't think you need to have both. You can just created the button where you want it.
Just for reference I created a Label and a Button packed on different sides with a black background to show the transparency of the image.
Here is the code I used to test a gif I have that has transparency. I tested this on both python 3.6 and 2.7 just in case.
from tkinter import *
root = Tk()
def quitApp():
root.destroy()
background_img = PhotoImage(file="Colors/sa.gif")
scanBtn_img = PhotoImage(file="Colors/sa.gif")
background = Label(root,bg='black', image = background_img).pack(side = RIGHT)
quitButton = Button(bg='black', image=scanBtn_img, command = quitApp).pack(side = LEFT)
backgroundimage = background_img # keep a reference!
root.mainloop()
Update: I used the gif you link in the comment
Here is the result.
Update:
After doing some more digging I found what might work for Mac OS:
I don't have a Mac to test on right now so let me know if this works for you:
from tkinter import *
root = Tk()
# Hide the root window drag bar and close button
root.overrideredirect(True)
# Make the root window always on top
root.wm_attributes("-topmost", True)
# Make the window content area transparent
root.wm_attributes("-transparent", True)
# Set the root window background color to a transparent color
root.config(bg='systemTransparent')
def quitApp():
root.destroy()
background_img = PhotoImage(file="Colors/1.gif")
scanBtn_img = PhotoImage(file="Colors/1.gif")
background = Label(root,bg='black', image = background_img)
background.pack(side = RIGHT)
background.config(bg='systemTransparent')
quitButton = Button(bg='black', image=scanBtn_img, command = quitApp)
quitButton.pack(side = LEFT)
quitButton.config(bg='systemTransparent')
backgroundimage = background_img # keep a reference!
root.mainloop()

how to change labels background as same picture

I started to learn Python one month ago. Sorry if my question is not good, this is my first question here.
I have made a small game using tkinter, but I have a problem.
I made a big label with a picture on it as background. Whenever I make more labels with text on them, the text will have gray background. However what I want is for every text to have the picture that I already placed as background.
Here's some code to explain it:
from tkinter import*
x=Tk()
x.geometry("1000x1000")
z=PhotoImage(file="D:\\Blue.gif")
v=Label(x,text="hi",font=100,fg="red",compound=CENTER,image=z,width=1000,height=1000)
v.place(x=0,y=0)
v1=Label(x,text="OO",font=100,fg="red")
v1.place(x=300,y=400)
x.mainloop()
The v label works very well as long as I use compound with it. It shows the picture with the text "hi" on it.
However I want the v1 label to have the same background as v, instead of gray background.
All widgets have background - they can't be transparent.
You can use tk.Canvas to put text without background on image or transparent image on text.
effbot.org: Canvas, PhotoImage
#!/usr/bin/env python3
import tkinter as tk
from PIL import Image, ImageTk
# --- constants ---
WIDTH = 800
HEIGHT = 600
# --- main ---
root = tk.Tk()
c = tk.Canvas(root, width=WIDTH, height=HEIGHT)
c.pack()
# only GIF and PGM/PPM
#photo = tk.PhotoImage(file='test.gif')
# other formats
image = Image.open('test_transparent.png')
photo = ImageTk.PhotoImage(image)
# use in functions - solution for "garbage collector" problem
c.image = photo
i = c.create_image((WIDTH//2, HEIGHT//2), image=photo)
t = c.create_text((WIDTH//2, HEIGHT//2), text='Hello World')
root.mainloop()
Change order and you get image on text
t = c.create_text((WIDTH//2, HEIGHT//2), text='Hello World')
i = c.create_image((WIDTH//2, HEIGHT//2), image=photo)
test_transparent.png (image with transparent background)

Categories

Resources