Python Tkinter如何获取自定义输入弹窗类的extension_name变量值
问题场景
使用Tkinter开发GUI程序时,自定义了继承自Toplevel的专用输入弹窗,弹窗内包含Entry输入框、确认/取消按钮,需要获取用户操作后类中存储的extension_name值作为返回值,但用户输入操作时长不固定,无法直接在实例化弹窗后拿到正确值。
原有实现代码如下:
class ExtensionNamer(Toplevel): def __init__(self, master, x, y, *args, **kwargs): #Initialize the window Toplevel.__init__(self, master, *args, **kwargs) #Set basic window properties self.title("Extension Naming") self.geometry("300x100+{}+{}".format(x, y)) self.attributes("-topmost", True) self.resizable(False, False) self.grab_set() #Create the widgets self.extension_name_label = Label(self, text="Extension Name:", font=medium_font) self.extension_name_label.place(relx=0.5, rely=.15, anchor=CENTER) self.extension_name_entry = Entry(self, font=normal_font, width=20, justify=CENTER) self.extension_name_entry.place(relx=0.5, rely=.5, anchor=CENTER) self.confirm_button = Button(self, text="Confirm", font=normal_font, command=self.confirm) self.confirm_button.pack(anchor=S, side=LEFT) self.cancel_button = Button(self, text="Cancel", font=normal_font, command=self.cancel) self.cancel_button.pack(anchor=S, side=RIGHT) self.protocol("WM_DELETE_WINDOW", self.cancel) def confirm(self): #Confirm the extension name self.extension_name = self.extension_name_entry.get() if ".xt" not in self.extension_name: self.extension_name += ".xt" self.destroy() def cancel(self): #Cancel the extension name self.extension_name = "NewXT.xt" self.destroy() ... def add_tab(self, event=None): #Adds a new tab tab_name = ExtensionNamer(self, self.winfo_x(), self.winfo_y(), color_mode=self.color_mode)
解决方法
核心问题是原有代码只调用了grab_set()独占焦点,没有阻塞执行流程,实例化弹窗后代码会立刻向下执行,此时用户还未完成输入,自然拿不到值。只需要加wait_window()方法阻塞等待窗口销毁即可,具体修改点如下:
- 在
ExtensionNamer类的__init__方法中提前初始化extension_name属性,避免极端场景下属性不存在抛出异常 - 把
grab_set()移动到组件、事件绑定完成后调用,再追加self.wait_window(),该方法会暂停当前执行流程,直到弹窗被销毁才会继续向后执行 - 弹窗实例化完成后,直接读取实例的
extension_name属性就能拿到最终值
修改后的可运行代码片段:
class ExtensionNamer(Toplevel): def __init__(self, master, x, y, *args, **kwargs): #Initialize the window Toplevel.__init__(self, master, *args, **kwargs) # 提前初始化返回值默认值 self.extension_name = "NewXT.xt" #Set basic window properties self.title("Extension Naming") self.geometry("300x100+{}+{}".format(x, y)) self.attributes("-topmost", True) self.resizable(False, False) #Create the widgets self.extension_name_label = Label(self, text="Extension Name:", font=medium_font) self.extension_name_label.place(relx=0.5, rely=.15, anchor=CENTER) self.extension_name_entry = Entry(self, font=normal_font, width=20, justify=CENTER) self.extension_name_entry.place(relx=0.5, rely=.5, anchor=CENTER) self.confirm_button = Button(self, text="Confirm", font=normal_font, command=self.confirm) self.confirm_button.pack(anchor=S, side=LEFT) self.cancel_button = Button(self, text="Cancel", font=normal_font, command=self.cancel) self.cancel_button.pack(anchor=S, side=RIGHT) self.protocol("WM_DELETE_WINDOW", self.cancel) # 独占焦点 + 阻塞等待窗口销毁 self.grab_set() self.wait_window() def confirm(self): #Confirm the extension name self.extension_name = self.extension_name_entry.get() if ".xt" not in self.extension_name: self.extension_name += ".xt" self.destroy() def cancel(self): #Cancel the extension name self.extension_name = "NewXT.xt" self.destroy() ... def add_tab(self, event=None): #Adds a new tab name_dialog = ExtensionNamer(self, self.winfo_x(), self.winfo_y(), color_mode=self.color_mode) tab_name = name_dialog.extension_name # 后续编写新建标签页的逻辑即可
原理说明
grab_set()仅能实现弹窗模态,阻止用户和主窗口交互,不会阻塞代码执行流程wait_window()是Tkinter内置的窗口状态监听方法,会持续hold住当前执行流,直到目标窗口被销毁才放行,刚好匹配「等待用户完成输入操作后再获取值」的需求- 你在
confirm和cancel方法中,调用destroy()销毁窗口前就已经给self.extension_name完成了赋值,等wait_window()执行结束、执行流回到add_tab方法时,直接读取实例属性就能拿到正确结果。
内容的提问来源于stack exchange,提问作者TRCK
相关产品推荐
相关产品推荐

