Tkinter继承下Scrabble GUI开发的AttributeError问题排查
问题:Tkinter开发Scrabble GUI时出现AttributeError: Frame has no attribute letterBag
问题详情
用Tkinter开发Scrabble图形界面,运行代码时始终抛出AttributeError: Frame has no attribute letterBag。对比两段代码:无Tkinter GUI的版本运行正常,包含GUI的版本报错。
我猜想问题原因是:Tkinter组件初始化时传入的是Frame实例而非App类引用,导致LetterRack的master属性指向Frame,而Frame没有仅属于App类的letterBag属性。这个猜想是否正确?
无Tkinter GUI的正常代码
import random as r class App: def __init__(self): self.letterBag = LetterBag() self.letterRack = LetterRack(self) class LetterBag: def __init__(self): self.tilesLeft = 10 self.tileList = ["" for x in range(10)] def remove_tile(self): self.tilesLeft -= 1 return self.tileList.pop(r.randint(0,self.tilesLeft)) class LetterRack: def __init__(self,master): self.master = master #Master would be used for Tkinter widget instantiation self.tiles = [] self.replenish_tiles() def replenish_tiles(self): while self.master.letterBag.tilesLeft != 0 and len(self.tiles) < 7: self.add_tile() def add_tile(self): self.tiles.append("3")
带Tkinter GUI的报错代码
import random as r import tkinter as tk class App(tk.Tk): # Main class for the whole game def __init__(self): super().__init__() #Intiate tk.Tk() window self.configure(bg="#50c878") self.title("Scrabble") self.resizable(False,False) self.containerFrame1 = tk.Frame(master=self,bg="#50c878",width=43,height=100) self.containerFrame2 = tk.Frame(master=self,bg="#50c878",width=63,height=100) self.letterBag = LetterBag() self.letterRack = LetterRack(self.containerFrame1) self.letterRack.grid(row=1,column=0,pady=(1,2),padx=(2,1)) self.containerFrame1.grid(row=0,column=0) self.containerFrame2.grid(row=0,column=1) self.mainloop() class LetterBag: def __init__(self): self.tilesLeft = 10 self.tileList = ["" for x in range(10)] def remove_tile(self): self.tilesLeft -= 1 return self.tileList.pop(r.randint(0,self.tilesLeft)) class LetterRack(tk.Frame): #Class defining letter rack frame def __init__(self,master): super().__init__(master=master,bg="#FFFFFF",width=40,height=40) self.master = master self.tiles = [] self.replenish_tiles() def replenish_tiles(self): while self.master.letterBag.tilesLeft != 0 and len(self.tiles) < 7: self.add_tile() def add_tile(self): pass window = App()
解答
你的猜想完全正确。
问题根源
- 无GUI版本中,
LetterRack初始化时传入的是App类的实例(self),所以self.master指向App对象,能正常访问App的letterBag属性。 - 带GUI版本中,你创建
LetterRack时传入的是self.containerFrame1——这是一个tk.Frame实例,并非App类的实例。当replenish_tiles方法调用self.master.letterBag时,master是Frame对象,它没有letterBag属性,因此抛出错误。
修复方案
方案1:直接传入App实例并指定父容器
修改App类中创建LetterRack的代码,传入App实例:
self.letterRack = LetterRack(self)
然后修改LetterRack类,保存App实例引用,并将containerFrame1作为Tkinter组件的父容器:
class LetterRack(tk.Frame): def __init__(self, app): self.app = app # 保存App实例,用于访问letterBag super().__init__(master=app.containerFrame1, bg="#FFFFFF", width=40, height=40) self.tiles = [] self.replenish_tiles() def replenish_tiles(self): while self.app.letterBag.tilesLeft != 0 and len(self.tiles) < 7: self.add_tile()
方案2:通过Frame的层级向上访问App实例
利用Tkinter组件的层级关系,containerFrame1的master就是App实例,因此可以通过self.master.master访问App对象:
修改LetterRack的replenish_tiles方法:
def replenish_tiles(self): while self.master.master.letterBag.tilesLeft != 0 and len(self.tiles) < 7: self.add_tile()
这种方式无需修改初始化参数,但依赖组件层级结构,后续布局调整可能引发问题,推荐优先使用方案1。
内容的提问来源于stack exchange,提问作者Shaken not Stirred
相关产品推荐
相关产品推荐

