Scott Field
Scott Field

Reputation: 11

Why doesn't my '<<TreviewSelect>>' bind change the PhotoImage being displayed in the Tkinter Window when it is called?

I can display an image to the Label Widget without difficulty, however when I try to change the label widget image by using the '<>' bind to get a different image path string (which is then attached to a new PhotoImage class using the Retrieve_Image function), before being returned to the Label Widget. The program instead erases the current label widget content. (I know the treeview select is returning the correct image url because the Retrieve_Image function prints out the image string after each selection.

I have attempted to use a StringVar variable class to attempt to force the program to update the image string however this has been just as ineffective is using a regular string to store the image path.

I have altered the Retrieve_Image Function to return the image string instead of the PhotoImage object and instead assigned the label a new PhotoImage within the lambda function (This was also ineffective)

I am aware that the Tkinter PhotImage object clears when it is no longer in scope, however as the PhotoImage I am using was defined in the same main() function that it is called I am unsure why it keeps disappearing. Is it because it was called within a lambda function? and if so how can I alter my lambda function to ensure that my PhotoImage remains in scope? Or is the scope not the issue here?

Below I Have Embedded The Code Snippets I Believe To Be The Problem The Main Program (TransformersTCG_Deck_Builder.py) and other necessary data files Can Be Found At: https://github.com/perspace42/Transformers-TCG-Deck-Builder/blob/main/TransformersTCG_Deck_Builder.py

#Get Image From Selection
def Retrieve_Image(treeview):
    '''This function requires the treeview as a parameter in order to retrieve the image location string of the selected Battle or Transformer Card'''
    #Treeview Selection Returns a Tuple Which Must Be Converted Into a String To Turn Into An Image
    selection_tuple = treeview.selection()
    #Convert Tuple To String For Image Selection (image path is located at index 0 of the tuple)
    selection_string = selection_tuple[0]
    #Print To Verify What Program Has Retrieved
    print(selection_string)
    #Define Image amd Image Path
    image = PhotoImage(file = selection_string)
    return image


#set a variable class to display an image string in the card_preview_section frame
image_string = StringVar(card_preview_section,"Reckless-Charge.gif")
#set the image equal to the variable class string
card_image = PhotoImage(file = image_string.get())
image_label = Label(card_preview_section,image = card_image)
image_label.pack()
    
#Command Bindings For Treeview (Print Current Selection, and Display Image To Frame)

#Function Should Retrieve The Image (From TreeviewSelect), Then Display The Image Using a Label)
treeview_battle.bind('<<TreeviewSelect>>', lambda e:  image_label.config(image = Retrieve_Image(treeview_battle)))
treeview_transformer.bind('<<TreeviewSelect>>', lambda e: image_label.config(image = Retrieve_Image(treeview_transformer)))

Upvotes: 0

Views: 40

Answers (1)

acw1668
acw1668

Reputation: 46707

It is because the image is garbage collected as there is no variable referencing it.

Suggest to pass the label to the function and update the image of the label inside the function. Use an attribute of the label to store the reference of the image to avoid garbage collection:

def Retrieve_Image(treeview, label):
    '''This function requires the treeview as a parameter in order to retrieve the image location string of the selected Battle or Transformer Card'''
    #Treeview Selection Returns a Tuple Which Must Be Converted Into a String To Turn Into An Image
    selection_tuple = treeview.selection()
    #Convert Tuple To String For Image Selection (image path is located at index 0 of the tuple)
    selection_string = selection_tuple[0]
    #Print To Verify What Program Has Retrieved
    print(selection_string)
    #Define Image amd Image Path
    image = PhotoImage(file = selection_string)
    # update label
    label.config(image=image)
    label.image = image  # store the reference of the image
    return image # optional return
...

treeview_battle.bind('<<TreeviewSelect>>', lambda e:  Retrieve_Image(treeview_battle, image_label))
treeview_transformer.bind('<<TreeviewSelect>>', lambda e: Retrieve_Image(treeview_transformer, image_label))

Upvotes: 0

Related Questions