I am trying to display an image in tkinter treeview. I have been reading possible solutions but none seems to work, I keep getting a blank tree only with the column heading. For what I have been reading, I have to keep a reference to the PhotoImage, but regardless of how much I try it just won't happen. A simple code example can be found below:
import tkinter as tk
from tkinter import ttk
from PIL import ImageTk as itk
import PIL.Image
import io
s= tk.Tk()
s.title('No *£/**##* image showing')
s.geometry('400x400')
s.rowconfigure(1, weight = 1)
s.columnconfigure(1,weight=1)
headings=['Image']
p = '032f8072.gif'
img1 = PIL.Image.open('032f8072.gif')
#img1 = img1.resize((10,10))
img = itk.PhotoImage(img1)
tree = ttk.Treeview(s)
tree.grid(column=1,row=1,sticky='NSEW')
tree['columns']=headings
tree['show']='headings'
for i in headings:
tree.heading(i,text=i)
tree.column(0, width=125,stretch=True)
#tree.column(1, width=125,stretch=True)
tree.insert('','end','0', open =True, image= img)
tree.image = img
s.mainloop()
I have tried with .gif and .png, i have tried with both PIL.Image and Imagetk.PhotoImage togeter and individually. I have also tried keeping img inside a list to be called from the list to avoid a missing reference.
I really need to get this small piece of code right and I am really frustrated with this little piece holding me back. I would really appreciate if someone could help me with this.
kind regards
This took awhile to figure out! I eventually found this answer to a similar question from 10 months ago (not officially an answer but look in the comments under the question):
Treeview Image not displaying
The user said the comment solved their problem, so I tried applying it to your example. What the commenter means is that the line tree['show'] = 'headings' forces the Treeview to only display the headings, and not the main body of the tree. To fix this, replace that line with the following:
tree['show'] = ('headings', 'tree')
to show all of the tree, and the image should start showing up.
You can create the columns using tree['columns'], but as ne0n p1atypus say, you can't display them using tree['show']. You can still enter the name for the columns manually with explorer_tree.heading("#0",text="Image",anchor= 'center') note that '#0' refers to the column in which the image will be displayed. I didn't try entering the column name using for loop.
Also, when trying to construct a treeview to display images in different rows using a for loop, this algorithm has to be within the function that defines the treeview and all the PhotoImage objects must be append to a list to keep its reference, otherwise they'll be collected as garbage. I'll leave an example below.
global eow
global dffile
global temp_result
global explorer_tree
#Define window and treeview
explorer_headings = ["Name",'Code', 'Supplier Code']
temp_list=[]
eow= Toplevel(acm)
eow.title('Stock Explorer')
eow.geometry('400x650')
eow.geometry("+0+0")
eow.minsize(400,650)
eow.state('zoomed')
eow.grab_set()
#style
style2 = ttk.Style()
style2.theme_use("awdark")
style2.configure("2style.Treeview.Heading",font=('Calibri', 18,'bold')) # Modify the font of the headings
style2.configure("2style.Treeview", font=('Calibri', 20),rowheight=100)
eow['bg']='black'
#Columns and rows
eow.columnconfigure(0, weight=1)
eow.columnconfigure(1, weight =2)
eow.columnconfigure(2, weight =2)
eow.columnconfigure(3, weight =1)
eow.rowconfigure(1, weight=4)
eow.rowconfigure(2, weight=2)
eow.rowconfigure(3, weight=2)
eow.rowconfigure(4, weight=2)
eow.rowconfigure(5, weight=1)
#Treeview to display data
explorer_tree = ttk.Treeview(eow, style='2style.Treeview',height=3)
explorer_tree.grid(column=1,row=2,sticky='NSEW', columnspan=2, rowspan=2)
#treeview scrollbars
xscroll_file_data= tk.Scrollbar(eow, orient='horizontal', command= explorer_tree.xview)
yscroll_file_data= tk.Scrollbar(eow, orient='vertical', command= explorer_tree.yview)
xscroll_file_data.grid(column=1,row=5,sticky='NEW',columnspan=2)
yscroll_file_data.grid(column=3,row=2,sticky='WNS',rowspan= 3)
explorer_tree.configure(yscrollcommand=yscroll_file_data.set)
add_part_button = Button(eow, text='Add Part',font=('Calibri', 14,'bold'),
activebackground='white', activeforeground='black',relief='raised', borderwidth=5
, command = add_part_from_pic_list)
add_part_button.grid(column=1, row=5, sticky='NSEW', padx=100, pady=40)
notfound_button = Button(eow, text='Part Not In List',font=('Calibri', 14,'bold'),
activebackground='white', activeforeground='black',relief='raised', borderwidth=5)
notfound_button.grid(column=2, row=5, sticky='NSEW', padx=100, pady=40)
code_label = Label(eow, text='Code: '+str(code)+' Name: '+online_name,background='black',
foreground='white',font=('Calibri', 18))
code_label.grid(column=1,row=1, sticky = 'NSEW',pady=10, padx=20)
#Name the headings
explorer_tree['columns']=explorer_headings
explorer_tree.heading("#0",text="Image",anchor= 'center')
explorer_tree.heading(0,text="Name",anchor= 'center')
explorer_tree.heading(1,text="Code",anchor= 'center')
explorer_tree.heading(2,text="Supplier Code",anchor= 'center')
#Format the columns
explorer_tree.column('#0', width=130,stretch=False)
explorer_tree.column(0,width=200, anchor='center',stretch=True)
explorer_tree.column(1,width= 200, anchor='center', stretch=False)
explorer_tree.column(2, anchor='center',stretch=False)
explorer_tree.tag_configure('even',foreground='black',background='white')
children = explorer_tree.get_children()
eow.protocol("WM_DELETE_WINDOW",Instant_exit)
explorer_tree.bind("<Double-1>", add_part_from_pic_list)
#construct tree
temp_list=[]
for i in range(len(temp_result)):
for j in range(len(dffile['Name'])):
if temp_result[i] == dffile['Name'][j]:
children1 = explorer_tree.get_children()
temp_row = [dffile['Name'][j],dffile['Code'][j],dffile['Supplier Code'][j]]
p = temp_row[1]+".png"
pp = "images/"+temp_row[1]+".png"
np = 'images/noimage.png'
try:#Append the PhotoImage object to a list rather than to a variable This will avoid the image being collected as garbage
temp_list.append(ImageTk.PhotoImage(Image.open(pp).resize((100,100),Image.ANTIALIAS)))
except FileNotFoundError:
temp_list.append(ImageTk.PhotoImage(Image.open(np).resize((100,100),Image.ANTIALIAS)))
continue
if len(children1)%2 == 0: #When calling the image for tree.insert, call the image from the list i.e. temp_list[i]
explorer_tree.insert('','end',iid=(len(children1)), image=temp_list[i], values=(temp_row[0],temp_row[1],
temp_row[2]),tags=('even'))
else:
explorer_tree.insert('','end',iid=(len(children1)), image=temp_list[i], values=(temp_row[0], temp_row[1],
temp_row[2]),tags=('odd'))
eow.mainloop() ```
try this, for me worked.
tree = ttk.Treeview(master=canvas, columns=car_header, show="tree headings", height=11)
img = tk.PhotoImage(file=r"frames/imgs/image.gif")
tree.insert(parent="",index="end", image=img, text='Information', values=collection_tree[i], tags=('oddrow'))
tk.Label.image = img
I tried creating a program that will take in the symptoms of a person and return the disease they have. This is the GUI part of the project.
from tkinter import *
root = Tk()
root.title("Health GUI")
root.geometry("1000x625")
symptoms_list = []
def print_symptoms():
print(symptoms_list)
def typeSymptoms():
gap3 = Label(text="").pack()
symptoms_entry = Text(width=50, height=20)
symptoms_entry.pack()
symptoms_list.append(symptoms_entry.get(1.0, END))
done_symptoms = Button(text="I have written my symptoms", width=25, height=5, command=lol)
done_symptoms.pack()
gap1 = Label(text="").pack()
title = Label(text="HEALTH GUI", font=30).pack()
gap2 = Label(text="").pack()
start_button = Button(text="Click here to start", width=30, height=5, command=typeSymptoms, font=20).pack()
root.mainloop()
Just for simplicity, I tried printing out the symptoms given by the user to the console but it gives me a list with '\n'. Please help. Thanks!(PS: I lerned Tkinter day before yesterday so I don't know much)
At the moment, your variable symptoms_list just holds the contents of the newly created Text widget, since you append this content at startup.
If you want to add the symptoms to the list, you need to have your function lol() that you call when pressing the button.
This function should look something like:
def lol():
symptoms_text = symptoms_entry.get(1.0, END)
symptoms_list = symptoms_text.split('\n')
print_symptoms()
However, your widgets and the symptoms_list would have to be global variables in order for this program to work. It would probably be better, while you are getting acquainted with Tkinter, to learn how to create a dialog as Class with attributes. That makes sharing values between methods so much easier.
This is my first day using tkinter, and I wanted to know how to properly code what I have done.
What I wanted to make was a kind of diaporama so I wanted to find a way to display pictures in a canvas and have two buttons so I could go to the previous picture or the following one. The way I stored pictures is using a list lof numpy arrays, with l of size n, so I have n pictures and they are the same size. So I wrote the following code:
from tkinter import *
import numpy as np
from PIL import Image, ImageTk
import sys
sys.setrecursionlimit(10000) #I increased the recursion limit because I had some issues
l = [(255*np.random.rand(50,50)).astype(np.uint8) for i in range(105)] #this is a random list in case you want to test the code
def next(i,n):
if i == n-1:
return 0
else:
return i+1
def previous(i,n):
if i==0:
return n-1
else:
return i-1
window = Tk()
window.geometry("200x100+900+500")
def display(i):
#This is to clear my window at each iteration because I would like to keep the same window
for widget in window.winfo_children():
widget.destroy()
array = l[i] #this is the i-th picture
img = ImageTk.PhotoImage(image=Image.fromarray(array),master = window)
canvas = Canvas(window, width=48, height=48)
canvas.place(x=10, y=20)
canvas.create_image(0,0, anchor="nw", image=img)
Label(window, text="Picture n°"+str(i), fg="black").place(x=5, y=0)
Button(window, text ='Next',command=lambda: display(next(i,len(l)))).place(x=140, y=35)
Button(window, text ='Previous',command = lambda: display(previous(i,len(l)))).place(x=70, y=35)
window.mainloop()
display(0)
I know that is bad code and not the way it should be written. It is working fine but I need help to improve the code please.
You should only put the code of updating the image inside display() and create the interface outside the function. Then recursion is not needed.
Also a global variable is required to keep track the current index to the image list. This variable should be updated when Next or Previous button is clicked.
Below is a modified example:
from tkinter import *
import numpy as np
from PIL import Image, ImageTk
l = [(255*np.random.rand(50,50)).astype(np.uint8) for i in range(105)] #this is a random list in case you want to test the code
current = 0
def display(dir):
global current
# update "current" based on "dir"
current = (current + dir) % len(l)
# show the "current" image
image = ImageTk.PhotoImage(Image.fromarray(l[current]))
imgbox.config(image=image, text=f"Picture n°{current}")
imgbox.image = image # keep a reference to avoid "image" from being garbage collected
window = Tk()
window.geometry("200x100+900+500")
# use a label for showing image and text together
imgbox = Label(window, fg="black", compound="bottom", width=70)
imgbox.place(x=5, y=0)
Button(window, text ='Next', command=lambda: display(+1)).place(x=150, y=35)
Button(window, text ='Previous', command=lambda: display(-1)).place(x=80, y=35)
display(0) # show first image
window.mainloop()
I have an issue where my image label will not update. I have used a large combination of root.update() root.update_idletasks() etc, I have also gone through many posts around the internet attempting to use their solutions but to no avail.
I have the code split to one class and two functions, the first function will check if the user has the right spelling or not, the second will pick a new random word and image from a dict.
The issue is that the image will not update, the print command is working so the class and funcs are working fine.
here is the code thus far, I am new to using Class and init I thought the best way to test out the .update of tkinter is a spelling game
from tkinter import *
import random
words = {"apple": "apple.gif", "car": "car.gif"}
MAIN_FONT = "Helvetica", 16
root = Tk()
class mainFrame:
def __init__(self):
self.pick_random = "..."
#MAIN TITLE OF THE APP
main_title = Label(root, text="Spelling", font=MAIN_FONT)
main_title.pack()
#END OF MAIN TITLE
#START OF IMAGE
self.img = PhotoImage(file=self.pick_another() + ".png")
self.show_image = Label(root, image=self.img)
self.show_image.configure(image=self.img)
self.show_image.image = self.img
self.show_image.pack()
#END OF IMAGE
#START OF ENTRY AND BUTTON INPUTS
self.main_entry = Entry(root)
self.submit_btn = Button(root, text="Submit", command=self.submit)
self.main_entry.pack()
self.submit_btn.pack()
#END OF ENTRY AND BUTTON INPUTS
def submit(self):
if self.main_entry.get() == self.pick_random:
print("RIGHT")
self.pick_another()
else:
print("That's not right, try again")
def pick_another(self):
print("Called")
self.pick_random = random.choice(list(words.keys()))
print(self.pick_random)
root.update_idletasks()
return self.pick_random
app = mainFrame()
root.mainloop()
As I said this does kind of work, The first image will show up and inputting the correct spelling for the image will generate a new word but the image does not update.
I have spent a few days working on various scripts trying to get tkinter to update, but it will not.
I would be very grateful for any help in this
I have a button which recalls 24 values from a text file. I now want to recall these values using a tkinter Scale widget but obviously I will want these values to increase in increments of 1 up to the value that is stored in the text file, these values will all be different.
So, for example, a shortened version of my text file is:
C1=255
C2=254
C3=120
C4=60
C5=153
So at the minute, my button will instantly recall these values, but I no want to slowly increment all of them using a scale so that when the scale is at the top of its travel it will represent all of the numbers shown above.
Here is my code which will do what I want but using a button, I now need to change the button for a slider:
from Tkinter import *
master= Tk()
master.geometry('500x500+0+0')
def print_value(val):
print ("c1="+str (c1v.get()))
print ("c2="+str(c2v.get()))
c1v=DoubleVar()
c2v=DoubleVar()
c1 = Scale(master, from_=255, to=0, length =400,width =100, troughcolor = 'blue',command=print_value, variable =c1v)
c1.grid(row=1,column=1)
c2 = Scale(master, from_=255, to=0, length =400,width =100, troughcolor = 'blue',command=print_value, variable =c2v)
c2.grid(row=1,column=2)
def load_p1():
pass
lp1 = open("/home/pi/Desktop/IEP/test/preset_test.txt")
val1, val2 = (x.split("=")[1] for x in lp1)
c1.set(val1)
c2.set(val2)
lp1.close()
def record():
save_path = '/home/pi/Desktop/IEP/test'
name_of_file = ("preset_test")
completeName = os.path.join(save_path, name_of_file+".txt")
file1 = open(completeName , "w")
toFile = ("c1="+str (c1.get())+ "\n""c2="+str(c2.get()))
file1.write(toFile)
file1.close()
rec=Button(master, text="Record",width=20, height=10, bg='Red', command=record)
rec.grid(row=2, column=1)
load=Button(master, text="Load",width=20, height=10, bg='gold',command=load_p1)
load.grid(row=2, column=2)
master.mainloop()
The best place to start is to find a tkinter tutorial and learn the basics of tkinter, completely ignoring the problem you are trying to solve. Then, using what you've learned, try to solve your problem. When you get stuck on a specific problem come back here and show us what you've tried.