tkinter Frame取消停靠及窗口关闭事件处理相关问题
问题解答
1. 为什么调用wm manage后控件类型还是tkinter.Frame
wm_manage是Tcl/Tk底层提供的窗口管理能力,它只会修改控件对应底层窗口的渲染属性,让它脱离父窗口成为独立顶层窗口,不会改变Python层面的tkinter对象类型。你初始化时创建的就是Frame类实例,Python侧的类属性不会因为底层窗口行为变化而动态切换,因此打印类型还是<class 'tkinter.Frame'>,不会自动变为Toplevel类型。
2. 如何绑定独立窗口的关闭事件
protocol是仅Tk、Toplevel类封装的方法,Frame类本身没有实现该方法,直接调用自然会抛出AttributeError。可以用两种方案实现需求:
方案1:直接调用底层Tcl命令设置协议
直接绕过Python层的方法封装,调用Tk底层的wm protocol命令绑定关闭回调,示例代码:
def undock(self): self.parent.wm_manage(self.dockable_frame) self.dockable_frame.configure(bg='blue') # 直接调用底层命令设置关闭回调 self.tk.call('wm', 'protocol', self.dockable_frame, 'WM_DELETE_WINDOW', self.on_close_undocked) # 自定义关闭回调,示例为点击关闭自动停靠 def on_close_undocked(self): self.dock()
方案2:获取对应顶层窗口对象后调用protocol
通过控件的winfo_toplevel()方法拿到它当前对应的顶层窗口实例,再调用protocol方法:
def undock(self): self.parent.wm_manage(self.dockable_frame) self.dockable_frame.configure(bg='blue') # 获取当前对应的顶层窗口 undocked_win = self.dockable_frame.winfo_toplevel() undocked_win.protocol("WM_DELETE_WINDOW", self.on_close_undocked)
以下是修改后的完整可运行代码:
import tkinter as tk class BaseFrame(tk.Frame): def __init__(self, parent): tk.Frame.__init__(self, parent) self.parent = parent self.bmanage = tk.Button(self, text='undock', command = self.undock) self.bforget = tk.Button(self, text='dock', command = self.dock) self.bmanage.grid(row=0, column=0, padx=20, pady=20, sticky='nsew') self.bforget.grid(row=0, column=1, padx=20, pady=20, sticky='nsew') self.dockable_frame = tk.Frame(self, bg="red", height=100) self.dockable_frame.grid(row=1, column=0, padx=20, pady=20, columnspan=2, sticky='nsew') self.label = tk.Label(self.dockable_frame, text="hi") self.label.grid(row=0, column=0, padx=150, pady=20, sticky='nsew') def undock(self): self.parent.wm_manage(self.dockable_frame) self.dockable_frame.configure(bg='blue') # 绑定关闭回调 undocked_win = self.dockable_frame.winfo_toplevel() undocked_win.protocol("WM_DELETE_WINDOW", self.on_close_undocked) def dock(self): self.parent.wm_forget(self.dockable_frame) self.dockable_frame.grid() def on_close_undocked(self): # 点击关闭时自动停靠回原窗口 self.dock() if __name__ == "__main__": root = tk.Tk() base_frame = BaseFrame(root) base_frame.grid(row=0, column=0, padx=20, pady=20, sticky='nsew') root.mainloop()
内容的提问来源于stack exchange,提问作者user34884
相关产品推荐
相关产品推荐

