'Tkinter Label not updating image
Im trying to make my first Tkinter project and decided on a Chess game. Ive written most of the basic program but when I tried to execute the pre-programmed pawn movements the pawn images don't change even tho it seems like the module registers the movement.
Here is all the details:
The widget structure is just one frame with label widgets placed in a grid representing a classical chess board.
My program has two classes, boot and move. Both is called (instantiated?) directly. Boot creates the board layout and also the object called game containing two nested dictionaries game.pawns and game.squares .
game.pawns
game.pawns contains information about each pawn such as position ect and is reached like: game.pawns['B_Bishop_C']['pos'] where first letter is the color and the last letter is the horizontal starting position. More details about dictionary keys and values are the code (line 25) found in git.
game.squares
game.squares contains information about the squares such as if it is occupied and by which pawn. Also very importantly it contains the label widget with key ['wdgt']. Each square is reached with a string: '0 to 7' + 'A to H' so regular chess positioning but with one less index. Ex Upper left '0A', down right '7H'.
Ex: game.squares['0B']['widget'] would access the label widget where a black knight is standing (white at bottom).
Problem
So back to the problem: For some reason when I try to .config the label to change the image it doesn't change even tho the imaged shows as it is added with the winfo command.
Code
Here is the code where called when I move a pawn to a empty square(where the error is)
img = game.pawns[self.current_pawn]['img']
game.squares[pos]['wdgt'].image = img
game.squares[pos]['wdgt'].config(image=img)
#replace image of target square to the new pawn
game.squares[game.pawns[self.current_pawn]['pos']]['occ'] = None
#Changes occ of old square
game.pawns[self.current_pawn]['pos'] = pos
#changes moving pawn attribute position to new
game.squares[game.pawns[self.current_pawn]['pos']]['wdgt'].config(image = '')
#remvoes pawn from old square
game.squares[pos]['occ'] = pawn
#Changes occ of new square
Here is my GitHub:
https://gits-15.sys.kth.se/markusjs/Chess
Note:
Code from above is around line 250.
self.current_pawn is in same form as dict key for game.pawns
To run the code PIL and Tkitner is needed.
Also pawns must be in the folder with the relative path given when creating the pawns at line 122-149
From line 300 and down is only pawn movement code.
There are probably some undiscoverd problems in the program
Things I tried:
Referencing image.
Using image without alpha (transparency).
Tkinter Label does not show Image
All help is appreciated.
Solution 1:[1]
In your move function in line 315, you are reassigning the game.pawns dictionary with the new dictionary. But the original dictionary is not being passed to that function!
def move(self, event):
if self.is_white:
pawn = 'W_' + self.current_pawn[1:] # piece of current player color (whites or blacks)
else:
pawn = 'B_' + self.current_pawn[1:]
pos = str(self.row) + chr(self.col + ord('A')) #position of the square
# Save the current selected pawn in a variable to pass it to aftermove (with its new position) method
img = game.pawns[self.current_pawn]['img'] #image of moving pawn is saved on attribute img
game.squares[pos]['wdgt'].image = img #widget reference as key ('0B') and then attribute image from widget (tkinter label). No change done to image on widget
game.squares[pos]['wdgt'].config(image=img) #config widget gets image from attribute
game.squares[game.pawns[self.current_pawn]['pos']]['occ'] = None #square where the pawn is currently on gets empty occ (None)
game.pawns[self.current_pawn]['pos'] = pos #dict key for moving pawn gets new position (position of new square)
game.squares[game.pawns[self.current_pawn]['pos']]['wdgt'].config(image = '') #config widget on label of new square and get rid of image
The game.pawns dictionary doesn't have the key of the pawn you are moving. Since you are reassigning the dict itself in this function, it would not work anyway. You need to pass that dict along with the new position of your pawn:
def move(self, event):
if self.is_white:
pawn = 'W_' + self.current_pawn[1:] # piece of current player color (whites or blacks)
else:
pawn = 'B_' + self.current_pawn[1:]
pos = str(self.row) + chr(self.col + ord('A')) #position of the square
# Save the current selected pawn in a variable to pass it to aftermove (with its new position) method
img = game.pawns[self.current_pawn]['img'] #image of moving pawn is saved on attribute img
game.squares[pos]['wdgt'].image = img #widget reference as key ('0B') and then attribute image from widget (tkinter label). No change done to image on widget
game.squares[pos]['wdgt'].config(image=img) #config widget gets image from attribute
game.squares[game.pawns[self.current_pawn]['pos']]['occ'] = None #square where the pawn is currently on gets empty occ (None)
temp = game.pawns #dict dictionary object holding all pawn info such as position ect gets saved in temp
game.pawns[self.current_pawn]['pos'] = pos #dict key for moving pawn gets new position (position of new square)
game.squares[game.pawns[self.current_pawn]['pos']]['wdgt'].config(image = '') #config widget on label of new square and get rid of image
aftermove(temp, pawn, pos)
Now the dict is passed along with the new position of your selected pawn:
def aftermove(dict, piece, pos): #takes dict with piece and its old position as input and the targets postion as a string 'A1'
if self.is_white:
pawn = 'W_' + self.current_pawn[1:] # piece of current player color (whites or blacks)
else:
pawn = 'B_' + self.current_pawn[1:]
game.squares[game.pawns[self.current_pawn]['pos']]['occ'] = None #square where the pawn is currently on gets empty occ (None)
temp = game.pawns #dict dictionary object holding all pawn info such as position ect gets saved in temp
game.pawns[self.current_pawn]['pos'] = pos #dict key for moving pawn gets new position (position of new square)
game.squares[game.pawns[self.current_pawn]['pos']]['wdgt'].config(image = '') #config widget on label of new square and get rid of image
aftermove(temp, pawn, pos) #after move function itself called again to retrace steps until no more pieces left to move hence no more recursion needed
return #return to stop recursion looping which causes program to crash when it reaches the maximum recursion depth limit for the amount of pawns there are.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | PJMan0300 |
