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

如何在 Tkinter 中将 Toplevel 作为 master 传入 Game 类

问题根源
  • Game是继承自tkinter.Frame的容器组件,实例化时没有传入指定父容器,tkinter会默认将其挂载到程序第一个创建的根主窗口(即欢迎窗口root)上,因此游戏内容全部显示在主窗口底部,新建的Toplevel子窗口只有一个测试按钮,没有游戏内容。
  • mains函数中额外添加了无意义的测试按钮,必须点击按钮才会创建游戏实例,不符合点击「New Game」直接启动游戏的需求。
  • Game类内部错误调用了self.mainloop():Tk程序全程只需要一个全局事件循环,主窗口已经启动了root.mainloop(),子窗口/组件内重复调用会造成事件循环嵌套,引发逻辑异常。
  • Tkinter中同一个组件不能同时调用pack()和grid()两种布局方法,否则会导致程序卡死。
修改步骤

仅需修改game_2048.py的代码,主欢迎窗口的核心逻辑无需改动。

1. 修改Game类构造函数

增加master参数接收外部传入的父窗口,将其传给父类Frame的初始化方法,删除多余的mainloop()调用。

原代码中的self.grid()是组件自行布局的逻辑,两种方案二选一即可:

方案A(保留原有布局,改动最小)

保留self.grid(),游戏帧会自动把自己添加到传入的父窗口中:

class Game(tkinter.Frame):
    def __init__(self, master):
        # 传入父容器给父类初始化
        super().__init__(master)
        # 保留原有的自动布局逻辑
        self.grid()
        self.master.title('2048')
 
        self.main_grid = tkinter.Frame(
            self, bg=c.GRID_COLOR, bd=3, width=400, height=400)
        self.main_grid.grid(pady=(80, 0))
        self.make_GUI()
        self.start_game()
 
        self.master.bind("<Left>", self.left)
        self.master.bind("<Right>", self.right)
        self.master.bind("<Up>", self.up)
        self.master.bind("<Down>", self.down)
        # 必须删除原有的 self.mainloop()

方案B(解耦布局,更规范)

删掉类内部的self.grid(),布局逻辑交给外部调用方控制:

class Game(tkinter.Frame):
    def __init__(self, master):
        super().__init__(master)
        self.master.title('2048')
 
        self.main_grid = tkinter.Frame(
            self, bg=c.GRID_COLOR, bd=3, width=400, height=400)
        self.main_grid.grid(pady=(80, 0))
        self.make_GUI()
        self.start_game()
 
        self.master.bind("<Left>", self.left)
        self.master.bind("<Right>", self.right)
        self.master.bind("<Up>", self.up)
        self.master.bind("<Down>", self.down)

2. 重写mains函数

创建Toplevel子窗口后,将其作为父容器传入Game即可。如果使用方案B,需要手动添加游戏帧的布局代码:

# 如果文件内使用 import tkinter 导入,Toplevel要写为 tkinter.Toplevel
def mains(root):
    # 创建游戏子窗口
    game_window = Toplevel(root)
    # 方案A直接实例化即可,无需额外布局
    Game(game_window)

    # 方案B需要手动布局游戏帧,撑满子窗口
    # game = Game(game_window)
    # game.pack(fill=BOTH, expand=True)

3. 修正单文件运行入口

如果需要直接运行game_2048.py启动游戏(不经过欢迎窗口),修改底部入口代码,自行创建根窗口并启动唯一的全局事件循环:

if __name__ == "__main__":
    root = tkinter.Tk()
    # 隐藏空白的默认根窗口,仅显示游戏子窗口
    root.withdraw()
    mains(root)
    # 全程序唯一的事件循环
    root.mainloop()
可选优化:禁止重复开启多个窗口

默认多次点击「New Game」会弹出多个游戏窗口,可以在主窗口中添加判断,游戏窗口打开时禁用按钮,关闭后恢复:

def start_new_game():
    # 禁用按钮防止重复点击
    button1.config(state=DISABLED)
    game_window = Toplevel(root)
    
    def on_game_close():
        game_window.destroy()
        # 关闭游戏后恢复按钮
        button1.config(state=NORMAL)
    
    # 绑定窗口关闭事件
    game_window.protocol("WM_DELETE_WINDOW", on_game_close)
    game_2048.Game(game_window)

# 将button1的command替换为start_new_game
button1 = Button(root, text="New Game", fg="black", bg="#ddf0d0", padx=3,
                 pady=3, font=('Helvetica', '12', 'bold'), 
                 activebackground="#94d3c3", command=start_new_game
                 )

内容的提问来源于stack exchange,提问作者BigPy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.22 07:06:07