I'm currently working on a Python GUI version of Reversi for a programming class. I've already programmed the game logic, and I'm currently trying to implement the GUI using Tkinter. I'm having some problems with resizing the game board (root window) and everything on it (canvases and shapes) proportionally. The game currently works, but everything that I've tried to get the board to resize correctly hasn't worked. The relevant code is as follows.
class OthelloApplication:
def __init__(self, game_state: othello.Othello):
self._game_state = game_state
self._game_state.new_game()
self._game_board = game_state.show_board()
self._root_window = tkinter.Tk()
for row in range(self._game_state.show_rows()):
for col in range(self._game_state.show_cols()):
canvas = tkinter.Canvas(self._root_window, width = 100, height = 100,
borderwidth = 0, highlightthickness = 1,
background = _BACKGROUND_COLOR, highlightbackground = 'black')
canvas.grid(row = row, column = col, padx = 0, pady = 0,
sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
self._root_window.rowconfigure(row, weight = 1)
self._root_window.columnconfigure(col, weight = 1)
self._turn_window = tkinter.Canvas(self._root_window, width = 200,
height = 100, highlightthickness = 0, background = 'white')
self._root_window.bind('<Button-1>', self._on_canvas_clicked)
self._root_window.bind('<Configure>', self.on_resize)
def draw_game_pieces(self) -> None:
for row in range(self._game_state.show_rows()):
for col in range(self._game_state.show_cols()):
if self._game_board[col][row] == ' ':
pass
else:
canvas = tkinter.Canvas(master = self._root_window, width = 100, height = 100,
borderwidth = 0, highlightthickness = 1,
background = _BACKGROUND_COLOR, highlightbackground = 'black')
canvas.grid(row = row, column = col, padx = 0, pady = 0,
sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
canvas.update()
canvas.create_oval(2, 2, canvas.winfo_width() - 2,
canvas.winfo_height() - 2, fill = self._which_color(col,
row), outline = self._which_color(col, row))
self._root_window.rowconfigure(row, weight = 1)
self._root_window.columnconfigure(col, weight = 1)
def display_turn(self) -> None:
if self._game_state.show_turn() == 'B':
turn = 'black'
else:
turn = 'white'
self._turn_window.grid(row = self._game_state.show_rows() // 2 - 1,
column = self._game_state.show_cols() + 1,
sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
self._turn_info = self._turn_window.create_text(10, 10,
font = 'Helvetica', anchor = 'nw')
self._turn_window.itemconfig(self._turn_info, text = 'Turn = ' + turn)
def on_resize(self, event: tkinter.Event) -> None:
self.draw_game_pieces()
def _which_color(self, col: int, row: int) -> str:
if self._game_board[col][row] == 'B':
return 'black'
elif self._game_board[col][row] == 'W':
return 'white'
def _on_canvas_clicked(self, event: tkinter.Event) -> (int):
print(event.widget.winfo_reqwidth(), event.widget.winfo_reqheight())
print(event.widget.winfo_width(), event.widget.winfo_height())
try:
grid_info = event.widget.grid_info()
move = (int(grid_info["row"]), int(grid_info["column"]))
self._game_state.player_move(move[1], move[0])
self.draw_game_pieces()
self.display_turn()
except AttributeError:
pass
except othello.InvalidMoveError:
print('Error: that wasn\'t a valid move.')
except othello.GameOverError:
print('The game is over.')
def start(self) -> None:
self.draw_game_pieces()
self.display_turn()
self._root_window.mainloop()
The draw_game_pieces() method draws the appropriately colored circle in the correct space on the board based on the size of the canvas on which it is being drawn.
My solution to my resize problem was binding on_resize() to the '<Configure>' event in the init method, but that causes the program to crash in a cycle of recursions. I'm new to tkinter and GUIs in general. Why is the on_resize() method being bound to '<Configure>' causing the program to crash?
Sorry about the messy code, I'm very much still working on it.
Thanks.