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
相关产品推荐
相关产品推荐

