python tkinter not display image in label - python

I am new to python.I have tried a code on how to display Texbox,image and button.But the image not displays
Please rectify my code to display the image!
My code:
import Tkinter
from Tkinter import *
class myproject(Tkinter.Tk):
def __init__(self,parent):
Tkinter.Tk.__init__(self)
self.button2()
self.text()
self.image()
def button2(self):
button2 = Tkinter.Button(self, text = "hello")
button2.grid(column=5,row=7)
def text(self):
text = Tkinter.Text(self, height=3, width=31)
text.grid(column=1,row=3)
text.insert(END, "Wiilliam Skakespeare")
def image(self):
logo = PhotoImage(file="linux.gif")
w1 = Tkinter.Label(self, image=logo)
w1.grid(column=5,row=7)
app = myproject(None)
app.mainloop()

You need to save the PhotoImage as a class variable so the reference can stay in memory. The following method for image() should work:
def image(self):
self.logo = Tkinter.PhotoImage(file="linux.gif")
w1 = Tkinter.Label(self, image=self.logo)
w1.grid(column=5,row=7)
This page provides a more in-depth explanation: Effbot PhotoImage. Specifically this section:
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.
To avoid this, the program must keep an extra reference to the image object.

Related

Display image button using function

I want to create many buttons. So, i have created a function and i call this function to create a button. The buttons have an Image so i have added on the parameter the link of the image when i call the function.
Knowing the Runtime error for Tkinter Image, i have used a list to save Image links.
The issue is that it display only one button. may be a problem with the list ?
from tkinter import *
app = Tk()
a = []
i = 0
def CreateButton (file, row):
global i
global ButtonCreationImg
global a
a.insert(i, file)
ButtonCreationImg = PhotoImage(file = a[i])
ButtonCreation = Button(app, image=ButtonCreationImg, border='0')
ButtonCreation.grid(row=row, column=0, columnspan=4, ipadx=0)
i += 1
CreateButton("bouton_1.png", 6)
CreateButton("bouton_2.png", 8)
app.mainloop()
I expect problem is with bug in PhotoImage and Garbage Collector which removes PhotoImage from memory when it is created in function and it is assigned to local variable - and which is removed by Garbage Collector when it exits from function.
You can read about this problem in Note on effbot.org: PhotoImage
I use button.img to assign PhotoImage to class so it will keep it in memory.
I also made other changes in code but they are not important for this problem.
import tkinter as tk
from PIL import ImageTk
# --- functions ---
def create_button(all_files, filename, row):
all_files.append(filename)
button_image = ImageTk.PhotoImage(file=all_files[-1])
button = tk.Button(app, image=button_image, border='0')
button.img = button_image # solution for bug with PhotoImage
button.grid(row=row, column=0, columnspan=4, ipadx=0)
# --- main ---
all_files = []
app = tk.Tk()
create_button(all_files, "bouton_1.png", 6)
create_button(all_files, "bouton_2.png", 8)
app.mainloop()

Use an image-button defined inside an object with TKinter

I'm trying to build a tkinter button with an image as background inside an object. It doesn't make any sense why the second implementation doesn't work !
Here are 3 very simple examples ; Who can explain the reason why the second implementation is not working?
(Python 3.6.4 :: Anaconda, Inc.)
1. Button created globally.
Works like a charm...
from tkinter import *
from PIL import Image, ImageTk
from numpy import random
w = Tk()
def cb():
print("Hello World")
image = ImageTk.PhotoImage(image=Image.fromarray(random.random((50,50))))
b = Button(w, text="text", command=cb, image=image)
b.pack()
w.mainloop()
2. Button created inside the object A with a background image
The button doesn't work when clicked and doesn't display the image :(. There's clearly a problem but I don't understand it...
from tkinter import *
from PIL import Image, ImageTk
from numpy import random
w = Tk()
class A():
def __init__(self, w):
image = ImageTk.PhotoImage(image=Image.fromarray(random.random((50,50))))
b = Button(w, text="text", command=self.cb, image=image)
b.pack()
def cb(self):
print("Hello World")
a = A(w)
w.mainloop()
3. Button created inside the object A without a background image
The button works properly, but I would like to display the image as well
from tkinter import *
from PIL import Image, ImageTk
from numpy import random
w = Tk()
class A():
def __init__(self, w):
image = ImageTk.PhotoImage(image=Image.fromarray(random.random((50,50))))
b = Button(w, text="text", command=self.cb)#, image=image)
b.pack()
def cb(self):
print("Hello World")
a = A(w)
w.mainloop()
You have 2 problems here.
The first problem is the image is not being saved after __init__. You probably know you need to save a reference to the image for it to be used in tkinter. You may not know that in a class if you do not assign the image to a class attribute it will not save the image after __init__.
So to fix the first issue you need change this:
image = ImageTk.PhotoImage(image=Image.fromarray(random.random((50,50))))
To this:
# add self. to make it a class attribute and keep the reference alive for the image.
self.image = ImageTk.PhotoImage(image=Image.fromarray(random.random((50,50))))
The 2nd issue you may not notice here is that your text will not display while loading an image. This is because you need to add the argument compound in order for tkinter to display both an image and text in the button. That said you also need to update the image argument to include the new self.image.
So change this:
b = Button(w, text="text", command=self.cb, image=image)
To this:
# added compound and change text color so you can see it.
b = Button(w, compound="center" , text="text", fg="white", command=self.cb, image=self.image)
Results:
I think I understood what happened. Thanks to the linked question what's happening in the second case is that your image gets garbage collected once the __init__ method is finished. As a result your image is not available anymore to the root application, so it cannot be binded to it.
The way to solve it is to make it a class attribute:
class A():
def __init__(self, w):
self.image = ImageTk.PhotoImage(image=Image.fromarray(random.random((50,50))))
b = Button(w, text="text", command=self.cb, image=self.image)
b.pack()
def cb(self):
print("Hello World")

Python tkinter: Replacing an image button with an image label

Hi I'm trying to make a code that would replace an image button with an image label when the button is pressed. But the window isn't updating so the new image doesn't became visible. Can anybody help me? If it is even possible to do that way.
There is the code I'm trying:
from tkinter import *
import time
gifdir = "./"
class Game:
def __init__(self):
self.__window = Tk()
igm = PhotoImage(file=gifdir+"empty.gif")
Button(self.__window, image=igm, command= self.change_picture)\
.grid(row=1, column=2, sticky=E)
def change_picture():
igm = PhotoImage(file=gifdir+"new.gif")
Label(self.__window, image=igm,)\
.grid(row=1, column=2, sticky=E)
self.__window.mainloop()
def main():
Game()
main()
When I add this code to the end:
self.__window.update_idletasks()
time.sleep(1)
the new picture is shown for a one second but I need to see it all the time and still be able to press other buttons.
I modified your code, as your code is very strangely designed, and incorrect IMO. This is the modified version:
from tkinter import *
import time
class Game:
def __init__(self):
self.__window = Tk()
self.gifdir = "./"
self.igm = PhotoImage(file=self.gifdir+"empty.gif")
self.btn = Button(self.__window, image=self.igm, command = self.change_picture)
self.btn.grid(row=1, column=2, sticky=E)
self.__window.mainloop()
def change_picture(self):
self.igm = PhotoImage(file=self.gifdir+"new.gif")
self.btn.configure(image = self.igm)
def main():
Game()
main()
In this new version, pressing the button, will change the image on it. Basically, in your class, you need to keep references to created widgets. Especially keeping a reference for PhotoImage is important, as if the reference is not kept, garbage collector will remove the image, when instance of PhotoImage will go out of scope in change_picture.

tkinter doesn't display image from outside the main file in a label [duplicate]

I expect the same output for both of the scripts below.
But I don't get the image on the button when I execute Script 1. However, Script 2 works well.
Script 1
from Tkinter import *
class fe:
def __init__(self,master):
self.b=Button(master,justify = LEFT)
photo=PhotoImage(file="mine32.gif")
self.b.config(image=photo,width="10",height="10")
self.b.pack(side=LEFT)
root = Tk()
front_end=fe(root)
root.mainloop()
Script 2
from Tkinter import *
root=Tk()
b=Button(root,justify = LEFT)
photo=PhotoImage(file="mine32.gif")
b.config(image=photo,width="10",height="10")
b.pack(side=LEFT)
root.mainloop()
The only reference to the image object is a local variable. When __init__ exits, the local variable is garbage collected so the image is destroyed. In the second example, because the image is created at the global level it never goes out of scope and is therefore never garbage collected.
To work around this, save a reference to the image. For example, instead of photo use self.photo.
its work
x1=Button(root)
photo=PhotoImage(file="Re.png")
x1.config(image=photo,width="40",height="40",activebackground="black"
,bg="black", bd=0,command=sil)
x1.place(relx=1,x=5, y=-5, anchor=NE)
but this is useless
def r():
x1=Button(root)
photo=PhotoImage(file="Re.png")
x1.config(image=photo,width="40",height="40",activebackground="black",
bg="black", bd=0,command=sil)
x1.place(relx=1,x=5, y=-5, anchor=NE)
r()
logo = PhotoImage(file = 'mine32.gif')
small_logo = logo.subsample(5, 5)
self.b.config(image = small_logo , compound = LEFT )
Unrelated answer, but this is the answer I was looking for when I first came here. Use this to resize the image before adding it to the button.
from PIL import Image, ImageTk
image = Image.open("path/to/image.png")
image = image.resize((25, 25), Image.ANTIALIAS)
self.reset_img = ImageTk.PhotoImage(image)
self.button = tk.Button(frame, image=self.reset_img)
from tkinter import *
root= Tk()
btnPlay = Button(root)
btnPlay.config(image=imgPlay, width="30", height="30")
btnPlay.grid(row=0, column=0)
root.mainloop()

I can't display text over my tkinter image

I am trying to display text on top of my image but I cannot do do this, can anyone help please.
Code:
# import Image and the graphics package Tkinter
import Tkinter
import Image, ImageTk
class simpleapp_tk(Tkinter.Tk):
def __init__(self,parent):
Tkinter.Tk.__init__(self,parent)
self.parent = parent
self.initialize()
def initialize(self):
## def create_widgets(self):
# create welcome label
label1 = Tkinter.Label(self, text = "Update User")
label1.grid(row = 0, column = 1, columnspan = 2, sticky = 'W')
# open a SPIDER image and convert to byte format
im = Image.open('C:\Users\JOHN\Desktop\key.jpg')
root = Tkinter.Tk() # A root window for displaying objects
# Convert the Image object into a TkPhoto object
tkimage = ImageTk.PhotoImage(im)
Tkinter.Label(root, image=tkimage).pack() # Put it in the display window
root.mainloop() # Start the GUI
The Label constructor takes a parameter compound. Pass the constructor both the image and text, and pass in compound as Tkinter.CENTER to overlap the text onto the image. Documentation for this feature is at http://effbot.org/tkinterbook/label.htm
import Tkinter
import Image, ImageTk
# open a SPIDER image and convert to byte format
im = Image.open(r'C:\Users\JOHN\Desktop\key.jpg')
root = Tkinter.Tk() # A root window for displaying objects
# Convert the Image object into a TkPhoto object
tkimage = ImageTk.PhotoImage(im)
Tkinter.Label(root, image=tkimage, text="Update User", compound=Tkinter.CENTER).pack() # Put it in the display window
root.mainloop() # Start the GUI
Also note, you're not supposed to mix pack and grid. You should choose one or the other. Reference: http://effbot.org/tkinterbook/grid.htm
P.S. just in case you meant you want the text to be vertically higher than the image, you can use the same code as above, except set compound=Tkinter.BOTTOM.

Categories

Resources