python canvas create image in loop

2.1k Views Asked by At

Hello i recently started studying tkinter and decided to pick up chess board game.
Below is my code:

import tkinter as tk

class GameBoard(tk.Frame):
    def __init__(self, parent, rows=8, columns=8, size=70, color1="white", color2="blue"):
        '''size is the size of a square, in pixels'''

        self.rows = rows
        self.columns = columns
        self.size = size
        self.color1 = color1
        self.color2 = color2
        self.pieces = {}

        canvas_width = columns * size
        canvas_height = rows * size

        tk.Frame.__init__(self, parent)
        self.canvas = tk.Canvas(self, borderwidth=0, highlightthickness=0,
                                width=canvas_width, height=canvas_height, background="bisque")
        self.canvas.pack(side="top", fill="both", expand=True, padx=2, pady=2)

root = tk.Tk()
board = GameBoard(root)
board.pack(side="top", fill="both", expand="true", padx=4, pady=4)

black_rook_l = tk.PhotoImage(file=black_rook_img)
black_rook_l = black_rook_l.subsample(2, 2)
board.addpiece("black_rook_l", black_rook_l, 0,0)

above code i is to add piece (black rook) to the board, which is working as expected.
below is the helper functions:

def addpiece(self, name, image, row=0, column=0):
    '''Add a piece to the playing board'''
    self.canvas.create_image(0,0, image=image, tags=(name, "piece"), anchor="c")
    self.placepiece(name, row, column)

def placepiece(self, name, row, column):
    '''Place a piece at the given row/column'''
    self.pieces[name] = (row, column)
    x0 = (column * self.size) + int(self.size/2)
    y0 = (row * self.size) + int(self.size/2)
    # print(name, x0, y0)
    self.canvas.coords(name, x0, y0)

But problem occurs when i try to place pawns with help of for loop. Below is the code:

for i in range(8):
    bname = tk.PhotoImage(file=black_pawn_img)
    bname = bname.subsample(2, 2)
    board.addpiece("black_pawn_"+str(i), bname, 1,i)

root.mainloop()

it is placing only last Pawn piece.

Please suggest/help me understand the issue.
Thanks in advance.

1

There are 1 best solutions below

2
Bryan Oakley On BEST ANSWER

The python image objects are getting destroyed by the garbage collector. You need to save references to the images. The first time through the loop, bname holds a reference to the first image that is created. In the next iteration, bname is modified to refer to the second image. Because of that, the first image no longer has a reference.

A simple way would be to keep track of them in the block of code that creates them:

images = []
for i in range(8):
    bname = tk.PhotoImage(file=black_pawn_img)
    bname = bname.subsample(2, 2)
    board.addpiece("black_pawn_"+str(i), bname, 1,i)
    images.append(bname)

Another way would be to have addpiece save them:

class GameBoard(...):
    def __init__(...):
        ...
        self.images = []
        ...
    def addpiece(self, name, image, row=0, column=0):
        ...
        self.images.append(image)
        ...