简体   繁体   中英

ttk.Notebook detach tabs

Problem

Detaching a frame from a `ttk.Notebook` i thought it would be worth a try to add this frame to a new `tk.Toplevel` window. This results in a
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.

Question

If that is implemented as documented, why can the frame not be gridded to a

descendant of the slave's parent.

as stated?

Code

#./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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM