Reputation: 65
I try to build an app with a notebook in which I don't really know the number of things that would go into it. I mean by things, tabs and subtabs and subtabs of subtabs. I decided to code a custom widget that will allow me to only give a dictionary in argument and voilà. I maybe do not seem clear so hear my example. Graphically it is fully working but when we look deeply into the notebook.tabs dictionary, well, it is not.
from tkinter import ttk
# Custom Tkinter Widget
class NotebookPlus(ttk.Notebook):
def __init__(self, *args, schema=None, **kwargs):
ttk.Notebook.__init__(self, *args, **kwargs)
self.schema = schema
self.tabs = {}
def superiterdict(dictionnary, lastK=None, lastN=None):
for key, value in dictionnary.items():
if lastN == None: lastN = self
# With multiple layer of notebook
if isinstance(value, dict):
# Create a new principal notebook
self.tabs[key] = {}
# Define the frame where the new notebook will be and where tabs are going to be
self.tabs[key]['frame'] = ttk.Frame(lastN)
self.tabs[key]['frame'].pack(fill='both')
# Define the new notebook
self.tabs[key]['notebook'] = ttk.Notebook(self.tabs[key]['frame'])
self.tabs[key]['notebook'].pack(fill='both')
lastN.add(self.tabs[key]['frame'], text=key)
# Define tabs
self.tabs[key]['tabs'] = {}
superiterdict(dictionnary=value, lastK=key, lastN=self.tabs[key]['notebook'])
else:
if self.tabs == {} and lastK == None:
self.tabs[lastK] = {'frame':None, 'notebook':lastN, 'tabs':{}}
self.tabs[lastK]['tabs'][key] = ttk.Frame(lastN)
self.tabs[lastK]['tabs'][key].pack(fill='both')
self.tabs[lastK]['notebook'].add(self.tabs[lastK]['tabs'][key], text=key)
superiterdict(self.schema)
root = tk.Tk()
frame = tk.Frame(root)
tabsSchema = {'TAB1': {'subtab11': None, 'subtab12': None},
'TAB2': {'subtab21': {'ssubtab211': None, 'ssubtab212': None}, 'subtab22': None}
}
notebook = NotebookPlus(root,schema=tabsSchema)
notebook.pack(fill='both')
root.mainloop()
My problem is that each time that the recursive function superiterdict is in front with a dictionary, it is treated as a completely new tab but sometimes it is not. To see that, here is the dictionary where everything is thrown in.
{
'TAB1': {
'frame': 'blob',
'notebook': 'blob',
'tabs': {
'subtab11': 'blob',
'subtab12': 'blob'
}
},
'TAB2': {
'frame': 'blob',
'notebook': 'blob',
'tabs': {
'subtab22':'blob'
}
},
'subtab21': {
'frame': 'blob',
'notebook': 'blob',
'tabs': {
'ssubtab211': 'blob',
'ssubtab212': 'blob'
}
}
}
I use 'blob' instead of '<tkinter.ttk.Frame object .!notebookplus.!frame2.!notebook.!frame2>' for readability. We can notice that the 'subtab21' is not in the tab dictionary of TAB2.
Upvotes: 1
Views: 142
Reputation: 3942
The problem is that you are using self.tabs
to add to the dictionary each time. This means that every time a key has a dictionary as it's value, that key is getting added to self.tabs
instead of the tabs dictionary of the parent. You want to add to the tabs
dictionary of the parent instead.
Here is a working superiterdict
function:
def superiterdict(dictionary, lastN = self, lastK = self.tabs):
# lastN: The widget to use as the parent.
# lastK: The "tabs" dictionary of the parent.
# If not given, it defaults to self.tabs.
for key, value in dictionary.items():
if isinstance(value, dict):
lastK[key] = {}
lastK[key]["frame"] = ttk.Frame(lastN)
lastK[key]["frame"].pack(fill = "both")
lastN.add(lastK[key]["frame"], text = key)
lastK[key]["notebook"] = ttk.Notebook(lastK[key]["frame"])
lastK[key]["notebook"].pack(fill = "both")
lastK[key]["tabs"] = {}
superiterdict(value, lastN = lastK[key]["notebook"], lastK = lastK[key]["tabs"])
else:
lastK[key] = ttk.Frame(lastN)
lastK[key].pack(fill = "both")
lastN.add(lastK[key], text = key)
This provides self.tabs
in the desired format.
Upvotes: 1