Tkinter应用Toplevel窗口不显示且跨类调用选择变量时触发AttributeError问题求助
Tkinter应用Toplevel窗口不显示且跨类调用选择变量时触发AttributeError问题求助
我仔细看了你的代码和遇到的两个问题:一是跨类调用选中的月份/年份时触发AttributeError,二是Toplevel选择窗口压根不显示。咱们一步步拆解解决:
一、解决AttributeError: 'InputWindow' object has no attribute 'selected_month'问题
这个错误的核心原因很直白:你在用户还没点击「Confirm」按钮的时候,就去读取selected_month和selected_year了。
看你的代码流程:
- 在
App的__init__里调用open_input_window() open_input_window()刚创建完InputWindow,立刻就调用handle_input_window_selections()- 这时候用户还没操作下拉框,更没点确认,
InputWindow里的selected_month和selected_year根本还没被赋值,自然会报错。
解决方案:用回调函数传递选中值
我们需要等用户点击「Confirm」后,再把选中的值传递给App,而不是主动去读。修改步骤如下:
- 修改
InputWindow类,让它接收一个回调函数,在用户确认后调用这个函数传递选中值:
class InputWindow(tk.Toplevel): def __init__(self, parent, on_confirm): super().__init__(parent) self.on_confirm = on_confirm # 保存回调函数 self.title("Schedule Selection") self.geometry("400x500") # 原有的月份、年份选择控件代码不变... def confirm_selections(self): if self.selections_are_valid(): self.selected_month = self.select_schedule_month.get() self.selected_year = self.select_schedule_year.get() self.withdraw() self.master.deiconify() self.on_confirm(self.selected_month, self.selected_year) # 调用回调,传递选中值
- 修改
App的open_input_window方法,把handle_input_window_selections作为回调传给InputWindow,去掉立刻调用的代码:
def open_input_window(self): self.input_window = InputWindow(self, self.handle_input_window_selections) # 删掉原来的 self.handle_input_window_selections() 调用
- 调整
handle_input_window_selections方法,直接接收选中的月份和年份,然后更新TitleFrame的标签:
def handle_input_window_selections(self, selected_month, selected_year): print(selected_month, selected_year) # 调用TitleFrame的方法更新标签 self.title_frame.update_calendar_labels(selected_month, selected_year)
- 给
TitleFrame添加更新标签的方法,让它能动态修改月份和年份的显示:
class TitleFrame(tk.Frame): def __init__(self, parent): super().__init__(parent) self.config(borderwidth=1, relief="raised", width=1300) self.grid(column=0, row=0, columnspan=35, padx=10, pady=10) # 原有的其他控件代码不变... self.Calendar_Month_label = tk.Label(self, text="Selected Month", font=("Calibri", 12)) self.Calendar_Month_label.grid(column=0, row=2) self.Calendar_Year_label = tk.Label(self, text="Selected year", font=("Calibri", 12)) self.Calendar_Year_label.grid(column=0, row=3) def update_calendar_labels(self, month, year): # 修改标签文本为选中的月份和年份 self.Calendar_Month_label.config(text=f"Selected Month: {month}") self.Calendar_Year_label.config(text=f"Selected Year: {year}")
二、解决Toplevel窗口不显示的问题
你的代码最后有一行app.withdraw(),而且App的__init__里是先创建InputWindow再处理主窗口,这可能导致窗口显示逻辑混乱。调整如下:
- 修改
App的__init__方法,先隐藏主窗口,再创建InputWindow:
class App(tk.Tk): def __init__(self): super().__init__() self.title("Schedule Window") self.geometry("1300x300") self.withdraw() # 先隐藏主窗口,等用户确认后再显示 self.open_input_window() # 原有的title_frame创建代码不变...
- 删掉代码最后一行的
app.withdraw():
app = App() # app.withdraw() # 把这行删掉 app.mainloop()
这样调整后,程序启动时会直接显示InputWindow选择窗口,用户点击确认后,主窗口才会显示,同时选中的月份和年份也会正确更新到TitleFrame里。
另外,注意你原来的handle_input_window_selections里重新创建了TitleFrame,这会导致原来的控件被覆盖,咱们上面的方案是直接更新现有TitleFrame的标签,避免重复创建。
备注:内容来源于stack exchange,提问作者Blue4Life90
相关产品推荐
相关产品推荐

