Search code examples
pythoncanvastkintertagsttk

Using a tkinter image canvas in a loop?


I recently started studying tkinter and decided to pick up this block breaker game and study/modify it.

So the problem occur in the following lines:

blocks = []
block.xLoc = 50
block.yLoc = 50
block.xsize = 40
block.ysize = 30
for x in range(4):
    for y in range(20):
        blockC = PhotoImage(file = "block.png")
        blockID = canvas.create_image(block.xLoc,block.yLoc,image=blockC)
        canvas.grid()
        blocks.append(blockID)
        block.xLoc += 40
    block.yLoc += 30
    block.xLoc = 50

I want to have multiple image blocks but instead its only give me a single block & other blocks are not visible but still functional (Ball bounces back).

How do I fix this?

This is the original code for comparison: (This one is working perfectly but its using a rectangle canvas.)

blocks = []
block.xLoc = 50
block.yLoc = 50
block.xsize = 40
block.ysize = 30
for x in range(4):
    for y in range(20):
        blockID = canvas.create_rectangle([block.xLoc, block.yLoc,
                                           block.xLoc+block.xsize,
                                           block.yLoc+block.ysize],
                                          fill="white")
        canvas.grid()
        blocks.append(blockID)
        block.xLoc += 40
    block.yLoc += 30
    block.xLoc = 50

Solution

  • As @Bryan Oakley pointed out, you need to keep references to the PhotoImage objects created in the loop somewhere so they aren't garbage collected as soon as you put a new value in the temporary blockC variable used inside the innermost loop.

    It's difficult to tell for sure from the fragment of code in your question, but something like the following should fix the problem. Since the image for all the blocks is the same, there's no reason to load 80 copies of it in the inner loop itself. Just load it once before entering the loop and use it over-and-over.

    blocks = []
    block.xLoc = 50
    block.yLoc = 50
    block.xsize = 40
    block.ysize = 30
    blockC = PhotoImage(file="block.png")  # moved outside loop
    for x in range(4):
        for y in range(20):
    
            blockID = canvas.create_image(block.xLoc, block.yLoc, image=blockC)
    
            canvas.grid()
            blocks.append(blockID)
            block.xLoc += 40
        block.yLoc += 30
        block.xLoc = 50