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
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)
        ...