Tkinter PhotoImage is returning 'pyimage1' instead of the actual image in treeview row

114 Views Asked by At

as the title suggests, im writing a program that returns data from a mongodb database and shows it in a treeview. This data includes a base64 encoded image. When I pull back the b64 image and decode it into a PhotoImage all goes well and I can set it in its respective row. However the row only displays "pyimage1", "pyimage2" etc.

Any help would be greatly appreciated. Below is my tkinter class that basically kicks off in buildUI() and is instantiated once from main. I know the image is being decoded properly because I can save it to a png file and open it to the correct image.

I just don't know why the treeview row is showing "pyimage" instead of the actual decoded png.

My Class

from tkinter import *
from tkinter.ttk import *
from PIL import Image, ImageTk
import io, os
import base64

class TableEditor:
    def __init__(self, root) -> None:
        self.root = root
        self.image_list = []
    
    def buildUI(self):
        self.configureStyle()
        self.addButtons()
        self.buildTable()

    def configureStyle(self):
        style = Style()
        style.configure('TButton', font='calibri 10 bold', background='#192428')
        style.configure('Treeview', font='calibri 10', background='#829ab1')
        style.configure('Button.TFrame', font='calibri 10', background='#192428')
    
    def addButtons(self):
        button_frame = Frame(self.root, style='Button.TFrame')
        button_frame.pack(pady=20)

        upload_excel = Button(button_frame, text="Upload Excel File", command=self.return_uploaded_students, cursor='hand2')
        upload_excel.grid(row=0, column=0, sticky=W, padx=10, pady=10)

        upload_pdf = Button(button_frame, text="Upload PDF File", command=crop_image, cursor='hand2')
        upload_pdf.grid(row=0, column=1, sticky=W, padx=10, pady=10)

        dump_to_csv = Button(button_frame, text="Dump Database to CSV", command=self.dump_db_csv, cursor='hand2')
        dump_to_csv.grid(row=0, column=2, sticky=W, padx=10, pady=10)


        self.search_entry = Entry(button_frame)
        self.search_entry.grid(row=0, column=3, sticky=E, padx=10, pady=10)
        search_button = Button(button_frame, text="Search", command=self.filter_table)
        search_button.grid(row=0, column=4, sticky=E, padx=0, pady=10)

    def buildTable(self):
        frame = Frame(self.root, name="studentTable")
        frame.pack(fill='both', expand=True)
        results = Mongo().return_certain_count_no_id(400)
        res = list(results)
        if len(res) != 0:

            keys = list(res[0].keys())
            self.tree = Treeview(frame, columns=keys, show='headings')

    
            for column in res[0].keys():
                self.tree.heading(column, text=column.upper())
                self.tree.column(column, width=100)


            self.tree.bind("<Double-1>", self.edit_item)
            self.tree.bind("<Button-3>", self.display_menu)
            self.tree["show"] = "headings"

            for row in res:
                b64_image = row["b64_image"]
                
                row["b64_image"] =""

                values = list(row.values())
                self.tree.insert("", "end", values=values)

                drawing_image = base64.b64decode(b64_image)
                final_drawing = PhotoImage(data=drawing_image)

                item = self.tree.get_children()[-1]
                self.tree.set(item, column="b64_image", value=final_drawing)
                self.image_list.append(final_drawing)


            scrollbar = Scrollbar(frame, orient="vertical", command=self.tree.yview)
            self.tree.configure(yscrollcommand=scrollbar.set)
            scrollbar.pack(side="right", fill="both")

            self.tree.pack(fill='both', expand=True)
        else:
            headings  =  [ "id", "name", "class", "teacher", "school", "location",  "year", 'image name', 'image',  "action", "b64_image"]
            self.tree = Treeview(frame, columns=headings, show='headings')

            for column in headings:
                self.tree.heading(column, text=column.upper())
                self.tree.column(column, width=100)
            self.tree.pack(fill='both', expand=True)
        

My Main:

from tkinter import *
from tkinter.ttk import *
from objects.table_editor import TableEditor

if __name__ == "__main__":
    root = Tk()
    root.geometry('1600x700')
    root.title("TemplateTool")
    root.iconbitmap("./assets/icon.ico")
    root.configure(background='#192428')
    TableEditor(root).buildUI()

    root.mainloop()

Im pretty stuck and new to tkinter so any help is greatly appreciated. Thanks!

I tried using PIL.ImageTK but that didnt seem to make a difference. As you can see in the screenshot it still shows pyimage.

1

There are 1 best solutions below

3
Jan_B On

Instead of using the value argument use image in self.tree.item:

In your TableEditor class in the buildTable method where you try to set the image as the value of the treeview row change this line:

self.tree.set(item, column="b64_image", value=final_drawing)

to

self.tree.item(item, image=final_drawing)

For reference see this post


To directly set the image in the first column change your loop in buildTable from:

# ...
for row in res:
    b64_image = row["b64_image"]
                
    row["b64_image"] =""

    values = list(row.values())
    self.tree.insert("", "end", values=values)

    drawing_image = base64.b64decode(b64_image)
    final_drawing = PhotoImage(data=drawing_image)

    item = self.tree.get_children()[-1]
    self.tree.set(item, column="b64_image", value=final_drawing)
    self.image_list.append(final_drawing)
# ...

to

# ...
for row in res:
    b64_image = row["b64_image"]

    row["b64_image"] = ""

    drawing_image = base64.b64decode(b64_image)
    final_drawing = PhotoImage(data=drawing_image)

    self.image_list.append(final_drawing)

    values = list(row.values())
    self.tree.insert("", "end", image=final_drawing, values=values)
# ...