Tkinter双可点击并排框架实现及代码优化求助
问题解决:双框架棋盘按钮点击失效与代码优化
核心问题分析
- 按钮点击功能失效:
select_piece方法中仅在self.squares字典中查找按钮对应的位置,但frame2的按钮存在self.squares2里,点击frame2按钮时,list(self.squares.values()).index(button)会因值不存在抛出错误,导致逻辑中断。 - 代码冗余:重复维护
self.squares和self.squares2两个结构完全一致的字典,增加了代码维护成本。
解决方案与优化代码
优化思路
- 用嵌套字典统一存储两个棋盘的按钮,避免重复变量。
- 修改按钮点击事件绑定逻辑,传递棋盘标识与按钮实例,让
select_piece能准确匹配位置。 - 重构重复代码块,通过遍历两个棋盘减少冗余逻辑。
优化后的完整代码
import tkinter as tk import string class Board(tk.Frame): def __init__(self, parent, length, width): super().__init__(parent) self.parent = parent self.length = length self.width = width self.config(height=100 * self.length, width=100 * self.width) # 初始化两个并排棋盘框架 self.left_board = tk.Frame(self) self.right_board = tk.Frame(self) self.left_board.pack(side='left', padx=20) self.right_board.pack(side='right', padx=20) self.pack() # 嵌套字典存储两个棋盘的按钮:key为棋盘标识,value为位置-按钮的映射 self.board_squares = { "left": {}, "right": {} } self.ranks = string.ascii_lowercase[:length] self.buttons_pressed = 0 self.turns = 0 # 记录选中信息:(棋盘标识, 位置, 按钮) self.selected = None # 图片字典(请替换为实际的图片加载逻辑) self.white_images = { "blank.png": tk.PhotoImage(file="blank.png"), "dirt.png": tk.PhotoImage(file="dirt.png"), "fire.png": tk.PhotoImage(file="fire.png"), "metal.png": tk.PhotoImage(file="metal.png"), "water.png": tk.PhotoImage(file="water.png"), "wood.png": tk.PhotoImage(file="wood.png") } self.square_color = "white" # 可自行修改棋盘颜色 self.set_squares() def select_piece(self, board_id, button): # 快速定位按钮对应的位置 pos = next((k for k, v in self.board_squares[board_id].items() if v == button), None) if not pos: return if self.buttons_pressed == 0: # 记录第一次选中的信息 self.selected = (board_id, pos, button) self.buttons_pressed += 1 elif self.buttons_pressed == 1: # 处理第二次选中的移动逻辑 target_board, target_pos, target_btn = board_id, pos, button src_board, src_pos, src_btn = self.selected # 防止选中同一位置 if src_board == target_board and src_pos == target_pos: self.buttons_pressed = 0 self.selected = None return # 执行棋子移动:复制图片到目标位置,源位置设为空白 target_btn.config(image=src_btn["image"]) target_btn.image = src_btn["image"] src_btn.config(image=self.white_images["blank.png"]) src_btn.image = self.white_images["blank.png"] # 重置状态 self.buttons_pressed = 0 self.selected = None self.turns += 1 def set_squares(self): # 遍历两个棋盘创建按钮并绑定事件 for board_id, frame in [("left", self.left_board), ("right", self.right_board)]: for x in range(self.length): for y in range(self.width): btn = tk.Button(frame, bg=self.square_color, activebackground="lawn green") btn.grid(row=self.length - 1 - x, column=y) pos = self.ranks[x] + str(y + 1) self.board_squares[board_id][pos] = btn # 绑定点击事件,传递棋盘标识和按钮实例 btn.config(command=lambda b_id=board_id, btn=btn: self.select_piece(b_id, btn)) def set_pieces(self): # 初始棋子位置映射 dict_rank1_pieces = {"a1": "dirt.png", "b1": "fire.png", "c1": "metal.png", "d1": "water.png", "e1": "wood.png"} # 为两个棋盘批量设置棋子 for board_id in self.board_squares: # 设置第一行的初始棋子 for pos, img_name in dict_rank1_pieces.items(): btn = self.board_squares[board_id][pos] btn.config(image=self.white_images[img_name]) btn.image = self.white_images[img_name] # 设置其余位置的空白棋子 for rank in range(2, self.length + 1): for file in range(self.width): pos = self.ranks[file] + str(rank) btn = self.board_squares[board_id][pos] btn.config(image=self.white_images["blank.png"]) btn.image = self.white_images["blank.png"] # 主程序入口 if __name__ == "__main__": root = tk.Tk() root.geometry("800x800") board = Board(root, 5, 5) board.set_pieces() root.mainloop()
关键优化点说明
- 统一存储结构:用
self.board_squares嵌套字典替代两个独立字典,同时管理左右棋盘按钮,消除冗余。 - 修复点击逻辑:点击事件传递棋盘标识,通过
next()快速匹配按钮位置,解决原代码只能查找单一字典的问题。 - 重构重复代码:设置棋子的逻辑通过遍历两个棋盘实现,减少重复代码块,提升可维护性。
- 状态管理优化:用
self.selected变量统一记录选中信息,替代多个零散变量,逻辑更清晰。
内容的提问来源于stack exchange,提问作者Willem Brock Smith
相关产品推荐
相关产品推荐

