Tkinter中无法从根窗口访问子框架创建的变量求助
问题原因
你在MainWindow的__init__方法里执行的print(self.folder_input_container.directory.get()),是在窗口刚初始化完成、还没有任何用户交互的时候就运行了——这时候directory这个StringVar还没被赋值,自然打印空字符串。而子类里的print是放在按钮点击的回调函数browse_button里,只有当用户点击按钮、选择完目录后才会执行,此时directory已经被设置为选中的路径,所以能正确打印。
Tkinter程序控制流程梳理
- 初始化阶段:
- 实例化
MainWindow,执行它的构造方法:- 先初始化Tk的根窗口对象
- 创建
FolderInputFrame子组件,执行子组件的构造方法:- 初始化Frame,调用
_widgets方法创建StringVar、按钮、输入框,并把这些组件布局到界面上
- 初始化Frame,调用
- 紧接着执行根类里的
print语句,这时候用户还没操作按钮,directory是空的
- 实例化
- 事件循环阶段:
- 程序进入Tk的主事件循环(你的代码里应该补充
app = MainWindow(); app.mainloop(),这是Tkinter程序必须的启动步骤),等待用户交互
- 程序进入Tk的主事件循环(你的代码里应该补充
- 用户交互触发回调:
- 用户点击按钮,触发
browse_button函数:- 弹出目录选择对话框,用户选完后返回目录路径
- 用
self.directory.set(dirname)更新StringVar的值,输入框会自动同步显示这个路径 - 执行子类里的
print,此时路径已经存在,所以打印正确内容
- 用户点击按钮,触发
解决方案
要让根类能在用户选择目录后获取到路径,可以用以下几种方式:
方式一:给子组件添加回调函数
让FolderInputFrame接受一个回调参数,当目录选择完成时通知根类:
import tkinter as tk from tkinter import filedialog class FolderInputFrame(tk.Frame): def __init__(self, parent, on_directory_selected=None): tk.Frame.__init__(self, parent) self.on_directory_selected = on_directory_selected self._widgets() self.pack() def _widgets(self): self.directory = tk.StringVar() buttonDir = tk.Button(self, text='Source Directory: ', command=self.browse_button) buttonDir.pack(side='left', padx=10, pady=10) dirEntry = tk.Entry(self, textvariable=self.directory, width=70) dirEntry.pack(side='left', padx=10, pady=10) def browse_button(self): dirname = filedialog.askdirectory(initialdir='/', title='Please select a directory') self.directory.set(dirname) print(f"子类获取到的目录:{self.directory.get()}") # 通知根类 if self.on_directory_selected: self.on_directory_selected(self.directory.get()) class MainWindow(tk.Tk): def __init__(self): tk.Tk.__init__(self) self.folder_input_container = FolderInputFrame(self, self.handle_directory_selected) def handle_directory_selected(self, dirname): print(f"根类获取到的目录:{dirname}") if __name__ == "__main__": app = MainWindow() app.mainloop()
方式二:监听StringVar的变化
利用Tkinter变量的trace_add方法,监听directory变量的写入事件,一旦值更新就触发根类的处理函数:
import tkinter as tk from tkinter import filedialog class FolderInputFrame(tk.Frame): def __init__(self, parent): tk.Frame.__init__(self, parent) self._widgets() self.pack() def _widgets(self): self.directory = tk.StringVar() buttonDir = tk.Button(self, text='Source Directory: ', command=self.browse_button) buttonDir.pack(side='left', padx=10, pady=10) dirEntry = tk.Entry(self, textvariable=self.directory, width=70) dirEntry.pack(side='left', padx=10, pady=10) def browse_button(self): dirname = filedialog.askdirectory(initialdir='/', title='Please select a directory') self.directory.set(dirname) print(f"子类获取到的目录:{self.directory.get()}") class MainWindow(tk.Tk): def __init__(self): tk.Tk.__init__(self) self.folder_input_container = FolderInputFrame(self) # 监听directory变量的写入变化 self.folder_input_container.directory.trace_add("write", self.on_directory_change) def on_directory_change(self, *args): dirname = self.folder_input_container.directory.get() print(f"根类监听获取到的目录:{dirname}") if __name__ == "__main__": app = MainWindow() app.mainloop()
内容的提问来源于stack exchange,提问作者s6292_1997
相关产品推荐
相关产品推荐

