0

I'm writing a code that will display a .png in a canvas widget whenever the user selects an item in a Treeview widget. When I run my code, the image only displays in the canvas when there is an error thrown in the selectedItems function. So far, it can be any error, but will not display the image unless an error is thrown. I have tried inserting a time delay and used a debugging tool but I still do not understand why this happens. When there is no error, the Treeview still generates an index for the selected item, but the canvas doesn't update with the picture. Can someone educate me?

import tkinter as tk
import tkinter.ttk as ttk
from PIL import Image, ImageTk

def selectedItems(event):
    item = tree.selection()
    item_iid = tree.selection()[0]
    parent_iid= tree.parent(item_iid)
    directory= r"..."
    if tree.item(parent_iid, "text") != "":
        imageFile= directory + tree.item(item_iid, "text")
        image_o= Image.open(imageFile)
        image_o.thumbnail([683, 384], Image.ANTIALIAS)
        image1= ImageTk.PhotoImage(image_o)
        canvas1.create_image((0, 0), anchor= "nw", image= image1)
        a= 'hello' + 7

tree.bind("<<TreeviewSelect>>", selectedItems)

This is the error I get:

Traceback (most recent call last):
  File "C:\Program Files\Python36\lib\tkinter\__init__.py", line 1699, in __call__
    return self.func(*args)
  File ".\front_end_DataManager.py", line 21, in selectedItems
    a= 'hello' + 7
TypeError: must be str, not int

I'm aware of the TypeError one. That's intentional to get the image to display. I think the problem is in the tkinter call function. Any ideas?

  • 1
    always put full error message (Traceback) in question (as text, not screenshot). There are other useful informations. – furas Dec 26 '17 at 23:15
  • 1
    At the _very least_ we need to be able to reproduce your error with the uploaded code. My guess though we'll eventually get to a point where you'll [need to use a global reference to your image](https://stackoverflow.com/q/3359717/7032856). – Nae Dec 26 '17 at 23:33
  • 1
    Thank you for the guidelines on question posting etiquette. I've updated my question to be more concise and to include the error messages. – Drew Wilkins Dec 26 '17 at 23:42
  • you can't add string `"hello"` and number 7 - you have to convert number into string `str(7)` to concatenate both `"hello" + str(7)` – furas Dec 26 '17 at 23:44
  • @furas I'm aware that strings don't work that way. That was a line that I inserted deliberately to get the image to display properly. I think Nae is on to something though. – Drew Wilkins Dec 26 '17 at 23:50
  • Your code now lacks completeness. There's a `tree` reference but it had never been declared, and also you should've kept `tkinter.Tk` reference and added `mainloop`. – Nae Dec 26 '17 at 23:53
  • Possible duplicate of [Cannot Display an Image in Tkinter](https://stackoverflow.com/questions/3359717/cannot-display-an-image-in-tkinter) – Nae Dec 26 '17 at 23:55

1 Answers1

0

You have problem with bug in tkinter which removes from memory image assigned to local variable in function - and then it doesn't display it. You have to assign it to global variable or class.

See global in code - this way image1 will be global variable, not local.

def selectedItems(event):
    global image1

    item = tree.selection()
    item_iid = tree.selection()[0]
    parent_iid = tree.parent(item_iid)
    directory = r"..."
    if tree.item(parent_iid, "text") != "":
        imageFile = directory + tree.item(item_iid, "text")
        image_o = Image.open(imageFile)
        image_o.thumbnail([683, 384], Image.ANTIALIAS)
        image1 = ImageTk.PhotoImage(image_o)
        canvas1.create_image((0, 0), anchor= "nw", image= image1)

See also "Note:" at the end of page The Tkinter PhotoImage Class

furas
  • 134,197
  • 12
  • 106
  • 148
  • Yep. That completely solved it. I had reviewed The Tkinter PhotoImage Class that you linked to earlier, and I saved the image to a variable that would be returned in the function. That didn't work, but making it global solves it entirely. Thank you. – Drew Wilkins Dec 27 '17 at 00:15
  • functions assigned by `bind()`/`command=`/`after()` are executed by `mainloop()` later but `mainloop()` doesn't assign returned values to global variables. It doesn't care of returned values. It skeeps them. – furas Dec 27 '17 at 00:30