How do I delete the Label I click on? - python

I have been working on a project where I use labels that I want to disappear on click, but it only deletes the last label that was created. Here's my code:
from tkinter import *
import tkinter
import random
from PIL import Image, ImageTk
from functools import partial
width1=1280
height1=720
canvas = tkinter.Canvas(width=width1,height=height1, bg = 'white')
canvas.pack()
def clicked(*args):
label.destroy()
def square():
global label
global img
sq_time = random.randrange(4000,6000)
x = random.randrange(100,width1-40,40)
y = random.randrange(40,height1-40,40)
label = Label(canvas, image = img)
label.place(x = x , y = y)
label.bind("<Button-1>",partial(clicked))
canvas.after(sq_time, square)
img = ImageTk.PhotoImage(Image.open('froggy.png'))
square()
mainloop()
froggy.png is a image that I have saved in the same folder as the code. Can someone tell me how do I delete the label that was clicked?

In tkinter event handler functions are automatically passed an event object argument that, among other things, has an attribute that identifies the widget that triggered them. This means you can use that instead of creating a partial to get the information needed.
from tkinter import *
import tkinter
import random
from PIL import Image, ImageTk
width1 = 1280
height1 = 720
canvas = tkinter.Canvas(width=width1, height=height1, bg='white')
canvas.pack()
def clicked(event):
event.widget.destroy()
def square():
global label
global img
sq_time = random.randrange(4000, 6000)
x = random.randrange(100, width1-40, 40)
y = random.randrange(40, height1-40, 40)
label = Label(canvas, image = img)
label.place(x=x, y=y)
label.bind("<Button-1>", clicked)
canvas.after(sq_time, square)
img = ImageTk.PhotoImage(Image.open('froggy.png'))
square()
mainloop()

def on_click():
label.after(1000, label.destroy)
Button(win, text="Delete", command=on_click).pack()

Related

How to change background color in quicker way?

I am doing a painting program where one can draw things, change the background color and save it as a file on the computer. Everything works except that changing the background color takes way too much time.
This is the code:
from tkinter import *
import tkinter.filedialog as tk
from tkinter import Menu
from tkinter.colorchooser import askcolor
from tkinter.filedialog import asksaveasfile,askopenfilename
import os
from PIL import Image as im
from PIL import ImageTk,ImageDraw,ImageColor
class P:
x=y=None
image=None
my_image=im.new("RGB",(600,600),(255,255,255))
draw=ImageDraw.Draw(my_image)
def __init__(self,window):
self.window = window
self.upper_frame = Frame(window)
self.upper_frame.grid(row=0,column=0, padx=10, pady=5,sticky="ew")
self.lower_frame = Frame(window)
self.lower_frame.grid(row=2, column=0, padx=10, pady=5,sticky="ew")
self.canvas= Canvas(self.lower_frame,width=700,height=530,bg="white")
self.canvas.grid()
self.bg = Button(self.upper_frame,text="Background",command= self.bgcolor) #change bg color
self.bg.grid(row=2,column=1,padx=(100,10))
self.upper_menu()
def bgcolor(self):
chosen_color = askcolor(color=self.canvas["bg"])[1]
self.canvas.configure(bg=chosen_color)
color_RGB = ImageColor.getcolor(chosen_color, "RGB")
img = self.my_image
for i in range(0,600):#pixels in width
for j in range(0,600): #height = 600 pix
data = img.getpixel((i,j)) #gives color of pixel
if (data[0]==255 and data[1]==255 and data[2]==255): #data represent RGB color
img.putpixel((i,j),color_RGB) #changes pixel color
def save_pic(self,event=None): #save image on comp.
my_file=asksaveasfile(mode="w",defaultextension=".png",filetypes=[("png files","*.png")],
initialdir="/home/b/",parent=window)
if my_file is not None:
path=os.path.abspath(my_file.name)
self.my_image.save(path)
def upper_menu(self):
self.menubar = Menu(window)
self.menu1 = Menu(self.menubar, tearoff=0)
self.menu1.add_command(label="Save pic", command=self.save_pic)
self.menu1.add_separator()
self.menu1.add_command(label="Exit", command=window.destroy)
self.menubar.add_cascade(label="Settings", menu=self.menu1)
self.menu2 = Menu(self.menubar, tearoff=0)
self.window.config(menu=self.menubar)
window = Tk()
window.geometry("720x590")
p = P(window)
window.mainloop()
I use the method bgcolor to change the background. How to make it work faster?
I suspect the problem is with calling putpixel 360,000 times. Instead, try creating the color data in the loop and then call putdata once after the loops have finished.
I'm not overly familiar with PIL, but this makes a huge difference when doing similar things with the tkinter PhotoImage class: doing one pixel at a time is slow, doing an array of pixels is fast.

How to make my variable update based on cursor position?

I tried to build off of the solution here. My code is:
from tkinter import mainloop, Tk, Frame, Button, Label, Canvas, PhotoImage, NW
from tkinter import ttk
from tkinter import filedialog
import tkinter as tk
from PIL import Image, ImageTk
class my_class(tk.Tk):
def __init__(self):
super().__init__()
self.geometry=('1400x1400')
self.filename = ''
my_notebook = ttk.Notebook(self)
my_notebook.pack(pady=5)
self.selections = Frame(my_notebook, width = 1100, height = 700)
self.selections.pack(fill = "both", expand=1)
my_notebook.add(self.selections, text = "Selections")
Button(self.selections, text = "Select an Image", command = self.get_image).place(x=10,y=40)
self.image_frame = Frame(my_notebook, width = 1100, height = 700)
self.image_frame.pack(fill = "both", expand=1)
my_notebook.add(self.image_frame, text = "Image")
self.my_canvas = Canvas(self.image_frame, width=800, height=600, bg="white")
self.my_canvas.pack()
self.rgb_var = tk.StringVar(self.image_frame, '0 0 0')
self.rgb_label = tk.Label(self.image_frame, textvariable = self.rgb_var)
self.rgb_label.pack()
self.image_frame.bind('<Motion>', lambda e: self.get_rgb(e))
def get_image(self):
self.filename = filedialog.askopenfilename(initialdir="D:/Python", title="select a file", filetypes = (("png files","*.png"),("jpg files","*.jpg")))
self.img = Image.open(self.filename)
self.img_rgb = self.img.convert('RGB')
dim_x, dim_y = self.img_rgb.size
self.img_tk = ImageTk.PhotoImage(self.img_rgb.resize((dim_x, dim_y)))
self.my_canvas.create_image(dim_x // 2, dim_y // 2, image = self.img_tk)
def get_rgb(self, event):
x, y = event.x, event.y
try:
rgb = self.img_rgb.getpixel((x, y))
self.rgb_var.set(rgb)
except IndexError:
pass # ignore errors if cursor is outside the image
if __name__ == '__main__':
app = my_class()
app.geometry=('1200x900')
app.mainloop()
I can use the button to select an image. Then I click the (Image) tab and see the selected image on the canvas.
I expected the (rgb_var) displayed under the image to update as I move the mouse pointer across the image. Instead the numbers under the image only update when the mouse pointer is in the frame, but outside the canvas. Also the numbers displayed seem to be unrelated to pixels in the image. How can I display the RGB values of a pixel that is (under the mouse pointer) when the mouse pointer is over the image?

How to get circles to appear over the video in canvas tkinter?

I have the below code:
import tkinter as tk, threading
from tkinter import *
import imageio
from PIL import Image, ImageTk
from random import *
video_name = "video.mp4" #This is your video file path
video = imageio.get_reader(video_name)
def stream(label):
for image in video.iter_data():
frame_image = ImageTk.PhotoImage(Image.fromarray(image))
label.config(image=frame_image)
label.image = frame_image
def circle():
global circ
x = randint(0, 299)
y = randint(0, 299)
diameter = randint(10, 100)
circ = canvas.create_oval(x, y, x + diameter, y + diameter, tags="circle")
canvas.tag_raise(circ)
if __name__ == "__main__":
root = tk.Tk()
canvas = Canvas(root, bg="green")
canvas.pack(expand=True, fill=BOTH)
my_label = tk.Label(canvas)
my_label.pack()
b = Button(canvas, text="Circle", command=circle)
b.pack()
thread = threading.Thread(target=stream, args=(my_label,))
thread.daemon = 1
thread.start()
root.mainloop()
It works fine, and the circles appear, but they go behind the video playing. How can I make the circles appear on top of the video?
Thanks!
You will need to use a text item on the canvas rather than a label. The canvas does not allow you to draw on top of widgets embedded in or on the canvas.

I need help displaying full screen images with tkinter

I am doing a people counter in raspberry pi. I want to display an one image if someone comes in, and another one if someone comes out. Right now i am using the code below (that i took from another question here xd) to change the image that tkinter is displaying. The problem with this is thay it only shows the picture cat.jpg for a second, and then it shows a black screen and nothing happends.
import sys
if sys.version_info[0] == 2: # the tkinter library changed it's name from Python 2 to 3.
import Tkinter
tkinter = Tkinter #I decided to use a library reference to avoid potential naming conflicts with people's programs.
else:
import tkinter
from PIL import Image, ImageTk
import time
def updateRoot(root,imagen):
pilImage = Image.open(imagen)
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.overrideredirect(1)
root.geometry("%dx%d+0+0" % (w, h))
root.focus_set()
root.bind("<Escape>", lambda e: (e.widget.withdraw(), e.widget.quit()))
canvas = tkinter.Canvas(root,width=w,height=h)
canvas.pack()
canvas.configure(background='black')
imgWidth, imgHeight = pilImage.size
if imgWidth > w or imgHeight > h:
ratio = min(w/imgWidth, h/imgHeight)
imgWidth = int(imgWidth*ratio)
imgHeight = int(imgHeight*ratio)
pilImage = pilImage.resize((imgWidth,imgHeight), Image.ANTIALIAS)
image = ImageTk.PhotoImage(pilImage)
imagesprite = canvas.create_image(w/2,h/2,image=image)
root.update()
root = tkinter.Tk()
updateRoot(root,"Cat.jpg")
time.timesleep(5)
updateRoot(root,"Dog.jpg")
Before this I used this code
import tkinter
from PIL import Image, ImageTk
from tkinter import ttk
def updateRoot(root,imagen):
image1 = Image.open(imagen)
image2 = ImageTk. PhotoImage(image1)
image_label = ttk. Label(root , image =image2)
image_label.place(x = 0 , y = 0)
root.update()
That works fine, but it's not full screen.
First you should do the followings outside updateRoot():
make root window fullscreen (you can simply use root.attributes('-fullscreen', 1))
bind the <Escape> key
create the canvas and create_image() (you can use Label to do the same thing)
Then just update the image inside updateRoot().
Also you should use after() instead of time.sleep().
Below is an example:
try:
import Tkinter as tkinter
except:
import tkinter
from PIL import Image, ImageTk
def updateRoot(imagen):
# resize the image to fill the whole screen
pilImage = Image.open(imagen)
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
image = ImageTk.PhotoImage(pilImage.resize((w,h)))
# update the image
canvas.itemconfig(imgbox, image=image)
# need to keep a reference of the image, otherwise it will be garbage collected
canvas.image = image
root = tkinter.Tk()
root.attributes('-fullscreen', 1)
root.bind('<Escape>', lambda _: root.destroy())
canvas = tkinter.Canvas(root, highlightthickness=0)
canvas.pack(fill=tkinter.BOTH, expand=1)
imgbox = canvas.create_image(0, 0, image=None, anchor='nw')
# show the first image
updateRoot('Cat.jpg')
# change the image 5 seconds later
root.after(5000, updateRoot, 'Dog.jpg')
root.mainloop()
Fixed your Black issue using labels, try this. i think you still need to resize image to fit screen
import sys
if sys.version_info[0] == 2: # the tkinter library changed it's name from Python 2 to 3.
import Tkinter
tkinter = Tkinter #I decided to use a library reference to avoid potential naming conflicts with people's programs.
else:
import tkinter
from PIL import Image, ImageTk
import time
from tkinter import *
import PIL.Image
def updateRoot(root,imagen):
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.overrideredirect(1)
root.geometry("%dx%d+0+0" % (w, h))
root.focus_set()
root.bind("<Escape>", lambda e: (e.widget.withdraw(), e.widget.quit()))
img = PIL.Image.open(imagen)
root.tkimage = ImageTk.PhotoImage(img)
Label(root,image = root.tkimage).place(x=0, y=0, relwidth=1, relheight=1)
root.update()
root = tkinter.Tk()
updateRoot(root,"Cat.jpg")
time.sleep(3)
updateRoot(root,"Dog.jpg")
root.mainloop()

tkinter wont display anything when using after() method

At first I implemented this code which uses classes and worked fine:
from Tkinter import *
import numpy as np
from PIL import Image,ImageTk
import time
#----------------------------------------------------------------------
class MainWindow():
#----------------
def __init__(self,main,pix):
# canvas for image
self.canvas = Canvas(main, width=424, height=424)
self.canvas.grid(row=0, column=0)
# images
self.im=Image.fromarray(pix.astype('uint8'))
self.photo = ImageTk.PhotoImage(image=self.im)
self.my_images = self.photo
self.my_image_number = 0
# set first image on canvas
self.image_on_canvas = self.canvas.create_image(0, 0, anchor = NW, image = self.my_images )
self.i=0
self.j=0
main.after(1,self.onButton,main,pix)# button to change image
main.update()
#----------------
def onButton(self,main,pix):
print self.i,self.j
if self.j==100:
return
pix[self.i][self.j]=255-pix[self.i][self.j]
self.i+=1
if self.i==100:
self.i=0
self.j+=1
self.im=Image.fromarray(pix.astype('uint8'))
self.photo = ImageTk.PhotoImage(image=self.im)
self.my_images = self.photo
self.canvas.itemconfig(self.image_on_canvas, image = self.my_images)
main.after(1,self.onButton,main,pix)
else:
main.after(0,self.onButton,main,pix)
#----------------------------------------------------------------------
root = Tk()
pix=np.array([[(i,j,255) for i in range(256)] for j in range(255,-1,-1)])
x=MainWindow(root,pix)
root.mainloop()
Later I tried to use the same functions without the class and it looks like this:
from Tkinter import *
import numpy as np
from PIL import Image,ImageTk
import time
def onButton(main,pix):
global i,j
if j==100:
return
pix[i][j]=255-pix[i][j]
i+=1
if i==100:
i=0
j+=1
im=Image.fromarray(pix.astype('uint8'))
photo = ImageTk.PhotoImage(image=im)
my_images = photo
canvas.itemconfig(image_on_canvas, image = my_images)
main.after(1,onButton,main,pix)
else:
main.after(0,onButton,main,pix)
root = Tk()
pix=np.array([[(i,j,255) for i in range(256)] for j in range(255,-1,-1)])
canvas = Canvas(root, width=424, height=424)
canvas.grid(row=0, column=0)
im=Image.fromarray(pix.astype('uint8'))
photo = ImageTk.PhotoImage(image=im)
image_on_canvas = canvas.create_image(0, 0, anchor = NW, image = photo )
i,j=0,0
root.after(1,onButton,root,pix)# button to change image
print "hi"
root.mainloop(f i==100:
i=0
j+=1
im=Image.fromarray(pix.astype('uint8'))
photo = ImageTk.PhotoImage(image=im)
my_images = photo
canvas.itemconfig(image_on_canvas, image = my_images)
main.after(1,onButton,main,pix)
else:
main.after(0,onButton,main,pix)
root = Tk()
pix=np.array([[(i,j,255) for i in range(256)] for j in range(255,-1,-1)])
canvas = Canvas(root, width=424, height=424)
canvas.grid(row=0, column=0)
im=Image.fromarray(pix.astype('uint8'))
photo = ImageTk.PhotoImage(image=im)
image_on_canvas = canvas.create_image(0, 0, anchor = NW, image = photo )
i,j=0,0
root.after(1,onButton,root,pix)# button to change image
print "hi"
root.mainloop()
Why does this not work? This is the first time I am working with tkinter, so I am probably missing something crucial. What do I need to change?
I'm curious why you need to implement such a thing without a class, but first let's look at your problem, namely the OnButton function.
You have already defined global variables i and j. But how about others?
All variables that you are trying to mutate (and keep value) must also be declared as global! This is a root of your problem and as for the answer to the question "why doesn't it work" - #PM 2Ring give you a good refer to photoimage docs.
Note: When a PhotoImage object is garbage-collected by Python (e.g. when you return from a function which stored an image in a local variable), the image is cleared even if it’s being displayed by a Tkinter widget.
try:
from tkinter import *
except ImportError:
from Tkinter import *
import numpy as np
from PIL import Image,ImageTk
def onButton():
global i, j, photo #, pix
print(i, j)
if j == 100:
return
pix[i][j] = 255-pix[i][j]
i += 1
if i == 100:
i = 0
j += 1
photo = ImageTk.PhotoImage(image=Image.fromarray(pix.astype('uint8')))
canvas.itemconfig(image_on_canvas, image=photo)
root.after(1, onButton)
else:
root.after(0, onButton)
root = Tk()
pix=np.array([[(i, j, 255) for i in range(256)] for j in range(255, -1, -1)])
canvas = Canvas(root, width=424, height=424)
canvas.grid(row=0, column=0)
photo = ImageTk.PhotoImage(image=Image.fromarray(pix.astype('uint8')))
image_on_canvas = canvas.create_image(0, 0, anchor=NW, image=photo)
i, j = 0, 0
root.after(1, onButton) # button to change image
print("hi")
root.mainloop()
And if there's no need for this variables outside function - then make'em local and move all relevant code into function!
After all, please, take a time to read this article. Maybe you change your mind about the classes (and about wildcard import).

Categories

Resources