I'm having trouble laying out two same ttk.Treeview
widgets using ttk.Notebook
and grid
layout manager. When I'm working with only one treeview (placed in a labelframe, that is placed in a frame (section), that is placed in yet another frame (main), that is placed in root), then everything works and I get the desired results:
But as soon as I try putting two such treeviews in a notebook, everything goes haywire, even though I don't change anything in the code, apart from adding a notebook:
Here's the code I prepared according to the SO guidelines to better illustrate the problem (I tried to make it as short as I could while retaining vital characteristics (like the columns layout and scrollbars) of the app it was taken out of) :
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("App")
mainframe = ttk.Frame(root)
mainframe.grid()
section = ttk.Frame(mainframe, padding=(0, 0, 10, 60))
section.grid(sticky="nsew")
labelframe = ttk.Labelframe(section, text="Title", padding=(5, 7, 5, 13))
labelframe.grid(sticky="nsew")
# styles
style = ttk.Style()
style.configure(
"App.Treeview",
font=("TkDefaultFont", 8),
rowheight=15
)
style.configure(
"App.Treeview.Heading",
font=("TkDefaultFont", 8)
)
def build_tree(parent):
# treeview
trv = ttk.Treeview(parent)
trv.configure(
style="App.Treeview",
height=19,
columns=("#1", "#2", "#3", "#4"),
displaycolumns="#all",
selectmode="browse"
)
trv.grid(column=0, row=0, sticky="nsew")
# treeview's scrollbars
sbar_vertical = ttk.Scrollbar(parent, orient=tk.VERTICAL, command=trv.yview)
sbar_vertical.grid(column=1, row=0, sticky="ns")
sbar_horizontal = ttk.Scrollbar(parent, orient=tk.HORIZONTAL, command=trv.xview)
sbar_horizontal.grid(column=0, row=1, sticky="we")
trv.configure(yscrollcommand=sbar_vertical.set, xscrollcommand=sbar_horizontal.set)
# treeview's columns
trv.heading("#1", text="Name_1")
trv.heading("#2", text="Pos")
trv.heading("#3", text="NT/R")
trv.heading("#4", text="★")
trv.column("#0", stretch=True, minwidth=70, width=49)
trv.column("#1", stretch=True, minwidth=97, width=49)
trv.column("#2", stretch=True, minwidth=35, width=49)
trv.column("#3", stretch=True, minwidth=40, width=49, anchor=tk.E)
trv.column("#4", stretch=True, minwidth=12, width=49)
return trv
# tree = build_tree(labelframe)
# notebook
notebook = ttk.Notebook(labelframe)
tree1 = build_tree(notebook)
tree2 = build_tree(notebook)
notebook.add(tree1, text="One")
notebook.add(tree2, text="Two")
notebook.grid(sticky="nsew")
root.resizable(False, False)
root.mainloop()
To switch between the first result and the second, one has to only uncomment the
# tree = build_tree(labelframe)
line and comment out the # notebook
section.
I tried giving the notebook height
and weight
option arguments in a constructor but nothing changed and also tried with adding
rowconfigure(0, weight=1)
columnconfigure(0, weight=1)
to a container on each level (mainframe
, section
and labelframe
) and even all down to the notebook and the treeviews (even though AFAIK this should only be necessary if the window was to be resizable) - obtaining exactly the same result.
My understanding was if widgets are placed in a grid
without any options passed to a grid()
call, then a widget placed decides how much space it needs and the grid
manager accommodates a given column's width (or a height in case of a row) to the highest value requested by the widget (of all managed in a given column or row). Then if such decided space is too big for some other widget that uses the same row/column, then it gets stretched (or no - according mainly to the sticky
option). If that understanding is correct, then I don't quite understand the notebook's behavior, especially as the alone treeview seems to perfectly adhere to it.
My environment: Ubuntu 17.10, Python 3.6.3, Tkinter 8.6. In case the treeview columns' setup looks somewhat peculiar - it was derived from a comment to this question and has to be like that to make use of the horizontal scrollbar.