Python Tkinter窗口/小部件按比例调整大小
我目前正在为一个编程类开发一个Python GUI版本的Reversi。我已经对游戏逻辑进行了编程,目前正在尝试使用Tkinter实现GUI。我在按比例调整游戏板(根窗口)和上面的所有内容(画布和形状)时遇到了一些问题。游戏目前运行正常,但我试图让棋盘正确调整大小的一切都没有起作用。有关守则如下Python Tkinter窗口/小部件按比例调整大小,python,user-interface,tkinter,Python,User Interface,Tkinter,我目前正在为一个编程类开发一个Python GUI版本的Reversi。我已经对游戏逻辑进行了编程,目前正在尝试使用Tkinter实现GUI。我在按比例调整游戏板(根窗口)和上面的所有内容(画布和形状)时遇到了一些问题。游戏目前运行正常,但我试图让棋盘正确调整大小的一切都没有起作用。有关守则如下 class OthelloApplication: def __init__(self, game_state: othello.Othello): self._game_sta
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()
class Otherlo应用程序:
定义初始(自我,游戏状态:Otherlo.Otherlo):
自我。\游戏\状态=游戏\状态
self._game_state.new_game()
self.\u game\u board=game\u state.show\u board()
self.\u root\u window=tkinter.Tk()
对于范围内的行(self.\u game\u state.show\u rows()):
对于范围内的列(self.\u game\u state.show\u cols()):
canvas=tkinter.canvas(自根窗口,宽度=100,高度=100,
borderwidth=0,highlightthickness=1,
背景=\背景\颜色,强光背景='黑色')
网格(行=行,列=列,padx=0,pady=0,
粘性=tkinter.N+tkinter.S+tkinter.E+tkinter.W)
self.\u root\u window.rowconfigure(行,权重=1)
self.\u root\u window.columnconfigure(列,权重=1)
self.\u turn\u window=tkinter.Canvas(self.\u root\u window,宽度=200,
高度=100,高光厚度=0,背景='白色')
self.\u root\u window.bind(“”,在画布上单击self.\u)
self.\u root\u window.bind(“”,self.on\u resize)
def draw_game_碎片(自身)->无:
对于范围内的行(self.\u game\u state.show\u rows()):
对于范围内的列(self.\u game\u state.show\u cols()):
如果自选游戏棋盘[col][row]='':
通过
其他:
canvas=tkinter.canvas(master=self.\u root\u窗口,宽度=100,高度=100,
borderwidth=0,highlightthickness=1,
背景=\背景\颜色,强光背景='黑色')
网格(行=行,列=列,padx=0,pady=0,
粘性=tkinter.N+tkinter.S+tkinter.E+tkinter.W)
canvas.update()
canvas.create_oval(2,2,canvas.winfo_width()-2,
canvas.winfo\u height()-2,fill=self.\u哪个颜色(col,
行),轮廓=自身颜色(列,行))
self.\u root\u window.rowconfigure(行,权重=1)
self.\u root\u window.columnconfigure(列,权重=1)
def显示\ U形转弯(自)->无:
如果self.\u game\u state.show\u turn()=“B”:
转弯=‘黑色’
其他:
转向=‘白色’
self.\u turn\u window.grid(row=self.\u game\u state.show\u rows()//2-1,
column=self.\u game\u state.show\u cols()+1,
粘性=tkinter.N+tkinter.S+tkinter.E+tkinter.W)
self.\u turn\u info=self.\u turn\u窗口。创建文本(10,10,
字体='Helvetica',锚点='nw')
self.\u turn\u window.itemconfig(self.\u turn\u info,text='turn='+turn)
def on_resize(自身,事件:tkinter.event)->无:
赛尔夫。抽签
def _哪个颜色(self,col:int,row:int)->str:
如果self.\u game\u board[col][row]=“B”:
返回“黑色”
elif self._game_board[col][row]=“W”:
返回“白色”
在画布上单击定义(self,事件:tkinter.event)->(int):
打印(event.widget.winfo_reqwidth(),event.widget.winfo_reqheight())
打印(event.widget.winfo_width(),event.widget.winfo_height())
尝试:
grid\u info=event.widget.grid\u info()
移动=(int(网格信息[“行])、int(网格信息[“列]))
自我。\游戏\状态。玩家\移动(移动[1],移动[0])
赛尔夫。抽签
self.display_turn()
除属性错误外:
通过
除Otherlo.InvalidMoveError外:
打印('错误:这不是有效的移动')
除了奥赛罗。加梅奥菲尔外:
打印('游戏结束')
def启动(自)->无:
赛尔夫。抽签
self.display_turn()
self.\u root\u window.mainloop()
draw\u game\u parties()
方法根据要绘制的画布的大小,在棋盘上正确的空间中绘制相应颜色的圆圈
我的调整大小问题的解决方案是将_resize()上的绑定到init方法中的'
事件,但这会导致程序在递归循环中崩溃。我对tkinter和GUIs都是新手。为什么将on_resize()
方法绑定到'
会导致程序崩溃
对不起,代码太乱了,我还在努力
谢谢。递归导致的崩溃可能是因为您的on\u resize
方法创建了新的小部件。下面是正在发生的事情:
小部件获取一个事件,该事件
调用_resize哪个
创建一个嵌套循环,其中
创建一个画布,其中
导致小部件中的配置更改
在嵌套循环中调用update,该循环
导致事件被处理,这
调用_resize,这
创建一个嵌套循环,其中
创建一个画布,其中
导致小部件中的配置更改
在嵌套循环中调用update,该循环
导致事件被处理,这
调用_resize,这
根据经验,除非你绝对确定你需要更新,否则你不应该调用update,即使这样,你也需要停下来仔细考虑一下。一个几乎永远不会被打破的规则是在func中调用update