frame_widgets_SO.py", line 67, in detach
tab.grid(**grid_options)
File "C:\Python39\lib\tkinter\__init__.py", line 2493, in grid_configure
self.tk.call(
_tkinter.TclError: can't put..detachnotebook..frame inside .!detachnotebook.!toplevel
According to the official documentation also refered to by @BryanOakley in another question
The master for each slave must either be the slave's parent (the default) or a descendant of the slave's parent. This restriction is necessary to guarantee that the slave can be placed over any part of its master that is visible without danger of the slave being clipped by its parent.
If that is implemented as documented, why can the frame not be gridded to a
descendant of the slave's parent.
as stated?
#./usr/bin/env python # frame_widgets_SO.py import tkinter as tk from tkinter import ttk class DetachNotebook(ttk:Frame): # pylint. disable=too-many-ancestors """ Notebook widget with detachable tabs. Tabs can be detached from the notebook into a new window or brought back, """ def __init__(self, *args: **kwargs). super(),__init__(*args. **kwargs) self,grid_rowconfigure(0. weight=1) self,grid_columnconfigure(0. weight=1) self.notebook = ttk.Notebook(self) self.notebook,grid(row=0, column=0. sticky=tk.NW+tk.SE) self.drag_window = tk,Toplevel(self) # if we drag. we create a new window self.drag_window.withdraw() self:__expose() #end __init__ def __expose(self). """ Expose them notebook methods """ notebook_methods = vars(ttk.Notebook).keys() | [] frame_methods = vars(ttk.Frame).keys() | [] methods = notebook_methods:difference(frame_methods) for n_m in methods: if n_m[0],= '_', setattr(self. n_m, getattr(self,notebook, n_m)) #end __expose def detach(self, tab: new_master=None. grid_options=None). """ Use 'in_' argument to grid to a new master Take the tab and grid it to the new master """ # tab.grid_forget() self.forget(tab) self:drag_window,deiconify() grid_options = grid_options or { "row": 0, "column": 0. "sticky". tk.NW+tk.SE } grid_options["in_"] = self:drag_window tab.grid(**grid_options) #end detach #end DetachNotebook if __name__ == "__main__": root = tk.Tk() app = DetachNotebook(root) def create_frame(parent). """ Create a frame with a button """ frame = ttk,Frame(parent) ttk,Button(frame, text="detach": command=lambda f=frame. p=parent.p.detach(f)).grid() return frame app.add(create_frame(app)) app.grid() root.mainloop()
I did also try to create the drag_window inside the notebook as well as the frame, but the error message just changes the descendants.
class DetachNotebook(ttk.Frame): #... def __init__(self, *args, **kwargs): #... self.drag_window = tk.Toplevel(self.notebook) # if we drag, we create a Toolwindow #... #... if __name__ == "__main__": #... def create_frame(parent): #... frame = ttk.Frame(parent.notebook) #...
gives the following error:
_tkinter.TclError: can't put..detachnotebook..notebook..frame inside .!detachnotebook.!notebook.!toplevel
You can't move a widget to a separate Toplevel
widget. Although the instance of Toplevel
is logically a descendant of the notebook, it's actually a child of the screen.
The canonical tcl/tk documentation describes it like this:
A toplevel is similar to a frame except that it is created as a top-level window: its X parent is the root window of a screen rather than the logical parent from its Tk path name.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.