How do I update images on a Tkinter Canvas? - python

I'm trying to make a script which will enable me to dynamically update an image object and then post the updated image to a Tkinter Canvas widget. The code here is prototype code, just to get the basics down. The aim here is to put a blue pixel on the image being displayed by the canvas, at the click location.
Something very strange is going on here. I'm using the Wing IDE, and if I run this code through the debugger, with a breakpoint at any line in the woohoo function, and then continue execution after hitting the breakpoint, the code works exactly as expected- putting a blue pixel on the image. If I run the code normally, or through the debugger with no breakpoints, the image is never updated. This leads me to the conclusion that there is some internal wizardry going on which I haven't got much hope of understanding without aid.
I'd really like to know the best way to go about this (or any way, I guess), and if someone could explain to me what's going on under the hood that'd be really cool. Thanks.
from Tkinter import *
from PIL import Image, ImageTk
def woohoo(event):
original.putpixel((event.x,event.y),(0,0,255))
newpic = ImageTk.PhotoImage(original)
c.create_image((0,0),image=newpic, anchor="nw")
main = Tk()
c = Canvas(main, width=300, height=300)
main.geometry("300x300+0+0")
c.pack()
original = Image.open("asc.bmp")
picture = ImageTk.PhotoImage(original)
c.create_image((0,0),image=picture, anchor="nw")
c.bind("<Button-1>", woohoo)
main.mainloop()

My guess is, you're creating a new image in a function. The reference to the image is a local variable. When the function exits, the reference is garbage collected which causes the new image to be destroyed. Most likely, running interactively causes the garbage collector to run differently (perhaps more lazily?)

Changed a little of the other post to work with Python 3+ :
from tkinter import *
def stuff(event):
global picture3
picture3 = PhotoImage(file='picture2.png')
c.itemconfigure(picture2, image = picture3)
main = Tk()
c = Canvas(main, width=300, height=300)
c.pack()
picture = PhotoImage(file='picture1.png')
picture2 = c.create_image(150,150,image=picture)
c.bind("<Button-1>", stuff)
main.mainloop()

try it like this:
from Tkinter import *
from PIL import Image, ImageTk
def woohoo(event):
global picture #
original.putpixel((event.x,event.y),(0,0,255))
picture = ImageTk.PhotoImage(original)#
c.itemconfigure(myimg, image=picture)#
main = Tk()
c = Canvas(main, width=300, height=300)
main.geometry("300x300+0+0")
c.pack()
original = Image.open("asc.bmp")
picture = ImageTk.PhotoImage(original)
myimg = c.create_image((0,0),image=picture, anchor="nw")#
c.bind("<Button-1>", woohoo)
main.mainloop()

Related

The background doesn't round the button tkinter

I am using tkinter to create a GUI. I use PIL to import an image as the background. Here is my code:
root = tk.Tk()
root.title("DFUInfo-v1")
img = ImageTk.PhotoImage(Image.open("background.jpg"))
l=Label(image=img)
l.pack()
root.configure(bg='white')
root.geometry("490x280")
In my app, buttons are rounded. But when I use the image, the background does not match the round buttons, here is the image:
Can somebody help me pls? Thanks
Here is how you can create rounded "buttons" in tkinter (what determines the visible shape is how the image looks):
from tkinter import Tk, Canvas
from PIL import Image, ImageTk
# use your images here
# open your images (my preference is to use `.open` before initialising `Tk`)
img = Image.open('rounded.png')
# resize to match window geometry
bg = Image.open('space.jpg').resize((500, 400))
# the function to call when button clicked
def func(event=None):
print('clicked')
root = Tk()
root.geometry('500x400')
# here are the converted images
photo = ImageTk.PhotoImage(img)
bg = ImageTk.PhotoImage(bg)
# from now on this will be the "root" window
canvas = Canvas(root, highlightthickness=0)
canvas.pack(fill='both', expand=True)
# add background
canvas.create_image(0, 0, image=bg, anchor='nw')
# create button and you have to use coordinates (probably can make
# custom grid system or sth)
btn = canvas.create_image(250, 200, image=photo, anchor='c')
# bind the "button" to clicking with left mouse button, similarly
# as `command` argument to `Button`
canvas.tag_bind(btn, '<Button-1>', func)
root.mainloop()
Most of the explanation is in the code comments, but note that the bound sequence works for the whole image but images are always square so you can click the button being outside of the visible part but only as far as the image goes, it is most certainly possible to create a button that doesn't have such issues but that requires some math
Important (suggestion):
I strongly advise against using wildcard (*) when importing something, You should either import what You need, e.g. from module import Class1, func_1, var_2 and so on or import the whole module: import module then You can also use an alias: import module as md or sth like that, the point is that don't import everything unless You actually know what You are doing; name clashes are the issue.

the garbage collector destroy my image and I can't see it

I've had this problem before and I solved it here, the thing is that for another program I used the same method canvas.create_image() and I couldn't see my image. My idea is, that the garbage collector destroy it before I see it on my canvas, but I don't know how to stop this. I saw this, but I didn't know how to apply to my program.
But if I write canvas.create_rectangle(50, 50, 70, 70), I works very well, so I don't understand. I also tried to add my image to a Label instead of putting it in my canvas, and I had the same problem of seeing anything. But I've never got an execution error.
this is my code :
from tkinter import *
root = Tk()
canvas = Canvas(root, bg="yellow")
dino = canvas.create_image(600, 200, image=PhotoImage(file='running_1.png'))
canvas.pack(fill="both", expand=True)
root.mainloop()
Try this -
from tkinter import *
root = Tk()
canvas = Canvas(root, bg="yellow")
running =PhotoImage(file='running_1.png')
dino = canvas.create_image(600, 200, image=running)
canvas.pack(fill="both", expand=True)
root.mainloop()
Your code doesn't work because you are referencing the PhotoImage inside the canvas.create_image. You should assign a variable for it and then use image=variable

Image does not show on button Tkinter

I'm trying to simply add an image to a tkinter button. I tried everything:
import tkinter as tk
root = tk.Tk()
root.geometry('300x300+300+150')
photo = tk.PhotoImage('home.gif')
btn = tk.Button(root, image = photo, width = 100, height = 100)
btn.image = photo # even with this does not work
btn.pack()
root.mainloop()
I also tried with PIL setting the photo variable equal to ImageTk.PhotoImage(Image.open('home.gif')), I tried easly the open function, the absolute path of the photo (and yes, the photo is inside the same directory of my script), but anything works. The window just pop up with a big button, without image inside.
UPDATE:
I tried with other images, and I noticed that some images are shown while others no. This is because the images with transparent background cause a bug or a problem to tkinter... so, I do not know if there's a way to solve this. On google I find out that some people use canvas but I actually need the image to be inside the button so I do not know how to do.
Please change your code as below
photo = tk.PhotoImage(file='home.gif')
because i changed the above code and it worked....

Tkinter canvas - time and hiding image

I am writing a python code using Tkinter/canvas.
root = tk.Tk()
canvas = tk.Canvas(root, width=1800, height=900, borderwidth=0, highlightthickness=0, bg="white")
canvas.pack()
photo = tk.PhotoImage(file='image2.png')
root.photo = photo
canvas.create_image(1000,500,image=photo)
this is my background which I work with, works perfectly fine, but then I have a little problem with some parts. I need to put another image there in 1 part of the loop/code/if and in another part I need to "hide" it so I can show it and hide whenever I want. This is how i create it, but I can't solve the hiding part.
shine = tk.PhotoImage(file='svetlo.png')
smaller_image = shine.subsample(6, 6)
Svetlo = canvas.create_image(260, 830, image=smaller_image)
and my second problem is how I show date and time. RN I am using this
time1 = canvas.create_text(1000,500,text = strftime('%H:%M:%S'))
But it show just one time and doesnt change (obviously) and I dont know, how to make it work. I tried to find a solution, but only thing I found was only label and it doesn't work with my canvas, I need that time at the canvas. Thank you

Possible race-condition when creating images in TKinter?

For fun, I'm creating a crappy helicopter/flappybird clone using tkinter and I've run into some really bizarre behavior with regards images apparently not showing up.
(btw, using python3)
So I started with the following code just to see if I could start getting things to draw:
from tkinter import *
from PIL import ImageTk
class Bird(object):
def __init__(self, canvas, x=0, y=0):
self.canvas = canvas
photo = ImageTk.PhotoImage(file="flappy.gif")
self.bird = self.canvas.create_image(x,y,image=photo)
class Environment(Canvas):
def __init__(self, master, width=500, height=500):
super(Environment, self).__init__(master, width=width, height=height)
self.pack()
self.master = master
self.bird = Bird(self)
if __name__=="__main__":
r = Tk()
env = Environment(r)
env.pack()
r.mainloop()
Image didn't appear, all I had was a blank canvas. I thought this was odd, so I started playing around to see why that might be the case. My next step was to test that I knew how to create images, so I just made my file a basic image create:
if __name__=="__main__":
r,c=get_canv()
c.pack()
img = ImageTk.PhotoImage(file="flappy.gif")
c.create_image(100,100,image=img)
r.mainloop()
And this, predictably, works fine. So, my syntax in the prior code seemed to be correct. This is when I stumbled on something a little confusing:
if __name__=="__main__":
r,c=get_canv()
c.pack()
c.create_image(100,100,image=ImageTk.PhotoImage(file="flappy.gif"))
r.mainloop()
This didn't draw. I'm left with a blank canvas again. This is what made me suspect that maybe there was some weird threading issue going on behind the scenes. Does Anyone know why the second snippet worked and the third snippet failed?
I've seen this a number of times already. The problem is that the PhotoImage is garbage collected even though it is used in the Label! To fix the problem, just bind it to a member variable of the GUI itself:
self.photo = ImageTk.PhotoImage(file="flappy.gif")
self.bird = self.canvas.create_image(x,y,image=self.photo)
The reason it works in your second example is that the img variable exists until after the mainloop method has finished, while in your third example, it exists only during the creation of the Label.

Categories

Resources