1

I'm getting some issues trying to creating canvas images, a class handles the creation of the images, and i want that the class creates as many images as the times that i call it.

My code is this

from tkinter import *
from random import *

canvas_width = 800
canvas_height = 800

master = Tk()
canvas = Canvas(master, width=canvas_width, height=canvas_height, bg="black")
canvas.pack()

def images():
    for _ in range(3):
        Image_creator().create_image()

class Image_creator:

    def create_image(self):

        start_x = randint(1, canvas_width//2)
        start_y = randint(1, canvas_height//2)

        img = PhotoImage(file="pac_inizio.png")
        master.img = img
        self.image = canvas.create_image(start_x, start_y, anchor=NW, image=img)

images()

mainloop()

Actually with this code is displayed only 1 of the 3 images, i think that the other 2 canvas images are created but without the image inside. I tried to change the create_image function for create buttons instead of canvas images and understand if it was actually as i thought. If u run the code with the modified function it diplays 3 buttons but only one with the image inside.

def create_image(self):

    start_x = randint(1, canvas_width//2)
    start_y = randint(1, canvas_height//2)

    img = PhotoImage(file="pac_inizio.png")
    master.img = img
    self.image = Button( anchor=NW, image=img)
    self.image.place(x=start_x, y=start_y)

I think that the issue is in the image reference but don't know how to solve it

Mat.C
  • 1,379
  • 2
  • 21
  • 43
  • I think the problem is that with `master.img = img` you at any time hold only a reference to _one_ of the images; the otehrs are garbage collected. Try making `master.img` a list or something like that. (Also, it seems kind of pointless to have a class just for the `create_image` method.) – tobias_k Feb 02 '19 at 14:45
  • Read [Why does Tkinter image not show up if created in a function?](https://stackoverflow.com/a/16424553/7414759) – stovfl Feb 02 '19 at 14:47

1 Answers1

0

You seem to be aware of the common problem of images in tkinter being garbage collected although they are still being used somewhere, unless there's an explicit reference to that images. Note, however, that with master.img = img you will always only have a reference to one of the three (identical) images. If those images are meant to be different in your actual code, make master.img a list (or use any other list in the global score to store the images).

However, since the images are the same, you could also just load the image once directly in the global scope, not in the method, and then use that image. Also, there's not much point in having that class just for that one method (more so since the instance is also garbage collected in the loop).

img = PhotoImage(file="pac_inizio.gif") # create once in global score
def create_image():                     # regular function, not method
    start_x = randint(1, canvas_width//2)
    start_y = randint(1, canvas_height//2)
    canvas.create_image(start_x, start_y, anchor=NW, image=img)
tobias_k
  • 81,265
  • 12
  • 120
  • 179
  • I think the actual problem here is not what you've described in the first paragraph. They are properly saving all three images in the class, but they aren't saving the instances of `Image_creator` class. Since that instance gets garbage-collected, the images within also get garbage-collected. – Bryan Oakley Feb 02 '19 at 15:51
  • @BryanOakley How so? Note that OP does `master.img = img`, not `self.img = img`, and `self.image = canvas.create_image(...)` will only safe the ID of the image object on the canvas, but not the actual `PhotoImage`, right? – tobias_k Feb 02 '19 at 17:40
  • Oh, wow, I didn't catch that. `master.img = ...` is not good. The part I had noticed was this: `Image_creator().create_image()` - the OP is creating a new instance of `Image_creator` for each image, but not saving those instances. I guess there are two problems in the code, not one. – Bryan Oakley Feb 02 '19 at 19:05
  • @BryanOakley Yes, I tried to point this out, too, but I actually don't think that this is much of a problem. The instance seems not to be needed at all, hence you could just make it a regular function. But of course it's good to point those things out, as they could hint to some misunderstanding of how things work or have to be done. – tobias_k Feb 02 '19 at 20:32