0

I'm trying to modify the displayed image on a canvas when a button is clicked on. I have an object "Window" which will contain my window layers. this object contain a canvas named "draw_frame" and a button named "source_button". I add the command "self.load_static_source" to my button but when i click on my button nothing happen.

(Not exactely nothing because i tried to add default background in the init scope and when i click on my button after that the image on the canvas just diseappeared and the new selected image wasn't draw).

Here is my code:

from tkinter import *
from tkinter import filedialog
from PIL import Image, ImageTk

DARK_THEME      = "grey"
LIGHT_THEME     = "white"
THEME           = LIGHT_THEME


class Window():

    # object constructor
    def __init__(self, root, theme):

        # Sections #
        self.toolbar_frame = LabelFrame(root, bg=theme, height="40")
        self.toolbar_frame.pack(side=TOP, fill=X)

        # Canvas #
        self.draw_frame = Canvas(root)
        self.draw_frame.pack(side=RIGHT, fill=BOTH, expand=True)
        self.frame = self.draw_frame.create_image(0, 0, anchor=NW)

        # Buttons #
        self.source_button = Button(self.toolbar_frame, text="Source", bg=theme, command= lambda: self.load_static_source("./Sources/"))
        self.source_button.pack(side=LEFT)


    # Load image with tk compatibility
    def load_image(self, path_):

        print(path_)  ### DEBUG ###
        image = Image.open(path_)
        return ImageTk.PhotoImage(image)


    # Change canvas source with static one
    def load_static_source(self, dir_):

        path_ = filedialog.askopenfilename(initialdir = dir_, title = "Select file", filetypes = (("jpeg files","*.jpg"),("all files","*.*")))
        self.draw_frame.itemconfig(self.frame, image=self.load_image(path_))



root = Tk()
Window(root, THEME)
root.mainloop()

I found an other post talking about that and i can't find difference between what i did and the given solution and that's why i don't understand why that code isn't working.

Here are the exemple i found and the related post:

from Tkinter import *

#----------------------------------------------------------------------

class MainWindow():

    #----------------

    def __init__(self, main):

        # canvas for image
        self.canvas = Canvas(main, width=60, height=60)
        self.canvas.grid(row=0, column=0)

        # images
        self.my_images = []
        self.my_images.append(PhotoImage(file = "ball1.gif"))
        self.my_images.append(PhotoImage(file = "ball2.gif"))
        self.my_images.append(PhotoImage(file = "ball3.gif"))
        self.my_image_number = 0

        # set first image on canvas
        self.image_on_canvas = self.canvas.create_image(0, 0, anchor = NW, image = self.my_images[self.my_image_number])

        # button to change image
        self.button = Button(main, text="Change", command=self.onButton)
        self.button.grid(row=1, column=0)

    #----------------

    def onButton(self):

        # next image
        self.my_image_number += 1

        # return to first image
        if self.my_image_number == len(self.my_images):
            self.my_image_number = 0

        # change image
        self.canvas.itemconfig(self.image_on_canvas, image = self.my_images[self.my_image_number])

#----------------------------------------------------------------------

root = Tk()
MainWindow(root)
root.mainloop()

Related post : stackoverflow topic

Xeyes
  • 583
  • 5
  • 25

2 Answers2

1

You need to keep a reference to the image. Here's a link to the effbot page describing it: https://effbot.org/tkinterbook/photoimage.htm

You must keep a reference to the image object in your Python program, either by storing it in a global variable, or by attaching it to another object.

The solution Xeyes wrote is right, and this page explains.

0

So i found the solution. A bit weird but it works. I have to save the image in a class attribute before i give it to the canvas itemconfig method.

It now looks like :

self.placeholder = self.load_image(path_)
self.draw_frame.itemconfig(self.frame, image=self.placeholder)

Instead of just :

self.draw_frame.itemconfig(self.frame, image=self.load_image(path_))
Xeyes
  • 583
  • 5
  • 25