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

Tkinter运行出现2个额外窗口及销毁报错问题求助

问题分析与解决

核心问题原因

  • 多根窗口创建:代码开头的Game=Tk()直接创建了一个Tk根窗口,而后续定义的Game类继承自tk.Tk,实例化时又创建了第二个根窗口,导致运行时弹出两个窗口。
  • 重复初始化Tk实例:Game类的__init__方法中同时调用了tk.Tk.__init__(self)和super().__init__(),这会重复初始化Tk的内部Tcl命令,销毁窗口时触发_tkinter.TclError: can't delete Tcl command错误。
  • 额外的帧实例创建:switchframe方法里的print(frameclass(self))会额外创建一个frameclass的实例,造成资源浪费和潜在冲突。
  • 图片引用问题:background作为全局变量,且backgroundlabel用place后没有保留引用,可能导致图片被垃圾回收而不显示。

修复后的代码

import tkinter as tk
from tkinter import ttk, font, messagebox
import shelve
from PIL import ImageTk, Image

class Game(tk.Tk):
    def __init__(self):
        super().__init__()  # 只保留一次Tk初始化调用
        self.geometry('992x558')
        # 将background设为实例属性,避免被垃圾回收
        self.background = ImageTk.PhotoImage(Image.open('background.png'), master=self)
        backgroundlabel = tk.Label(self, image=self.background)
        backgroundlabel.place(x=0, y=0)
        self.iconbitmap('icon.ico')
        self._frame = None
        self.switchframe(npcheck)

    def switchframe(self, frameclass):
        newframe = frameclass(self)
        # 移除多余的frameclass(self)调用,避免创建额外实例
        if self._frame is not None:
            self._frame.destroy()
        self._frame = newframe
        self._frame.grid()

class npcheck(tk.Frame):
    def __init__(self, master):
        super().__init__(master)
        # 使用master的background属性
        backgroundlabel = tk.Label(self, image=master.background)
        backgroundlabel.place(x=0, y=0)
        q = tk.Label(self, text='New or existing player?')
        q.grid(row=0, column=1, sticky=tk.W+tk.E, padx=50, pady=50)
        # 按钮绑定的类需提前定义,避免报错
        gobutton = tk.Button(self, text='New Player.', command=lambda: master.switchframe(accountcreation))
        gobutton.grid(row=1, column=0, sticky=tk.W, padx=50, pady=50)
        gobutton = tk.Button(self, text='Existing Account.', command=lambda: master.switchframe(login))
        gobutton.grid(row=1, column=2, sticky=tk.E, padx=50, pady=50)

# 补充实现按钮跳转的目标帧类
class accountcreation(tk.Frame):
    def __init__(self, master):
        super().__init__(master)
        tk.Label(self, text='账号创建页面').pack(pady=20)

class login(tk.Frame):
    def __init__(self, master):
        super().__init__(master)
        tk.Label(self, text='登录页面').pack(pady=20)

if __name__ == "__main__":
    game = Game()
    game.mainloop()

关键修改点说明

  • 删除全局的Game=Tk()语句,避免创建多余的根窗口。
  • 简化Game类的初始化逻辑,只保留super().__init__()完成Tk实例初始化,消除重复初始化导致的Tcl命令冲突。
  • 将background改为Game类的实例属性,子帧通过master.background引用,既避免全局变量污染,又防止图片被垃圾回收。
  • 移除switchframe方法中多余的print(frameclass(self))调用,避免创建无效的帧实例。
  • 补充accountcreation和login基础类实现,避免点击按钮时因类未定义报错(可替换为你自己的业务逻辑)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 20:58:09