You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tkinter双可点击并排框架实现及代码优化求助

问题解决:双框架棋盘按钮点击失效与代码优化

核心问题分析

  1. 按钮点击功能失效:select_piece方法中仅在self.squares字典中查找按钮对应的位置,但frame2的按钮存在self.squares2里,点击frame2按钮时,list(self.squares.values()).index(button)会因值不存在抛出错误,导致逻辑中断。
  2. 代码冗余:重复维护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()

关键优化点说明

  1. 统一存储结构:用self.board_squares嵌套字典替代两个独立字典,同时管理左右棋盘按钮,消除冗余。
  2. 修复点击逻辑:点击事件传递棋盘标识,通过next()快速匹配按钮位置,解决原代码只能查找单一字典的问题。
  3. 重构重复代码:设置棋子的逻辑通过遍历两个棋盘实现,减少重复代码块,提升可维护性。
  4. 状态管理优化:用self.selected变量统一记录选中信息,替代多个零散变量,逻辑更清晰。

内容的提问来源于stack exchange,提问作者Willem Brock Smith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 10:55:35