如何对包含两个ttk Treeview的ttk Notebook进行网格化,以便它扩展以填充其指定的网格单元格?

时间:2018-02-05 23:51:58

标签: python tkinter treeview grid-layout

我在使用ttk.Treeviewttk.Notebook布局管理器布置两个相同的grid小部件时遇到问题。当我只使用一个树视图(放在一个labelframe中,放在一个框架(部分)中时,它放在另一个框架中( main ),放在 root ),然后一切正常,我得到了预期的结果:

enter image description here

但是当我尝试在笔记本中放置两个这样的树视图时,一切都变得混乱,即使我没有改变代码中的任何内容,分开添加笔记本:

enter image description here

这里是我根据the SO guidelines编写的代码,以更好地说明问题(我试图尽可能缩短它,同时保留应用程序的重要特征(如列布局和滚动条)它被取出了:

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()

要在第一个结果和第二个结果之间切换,必须取消注释

# tree = build_tree(labelframe)

排除并注释掉# notebook部分。

我尝试在构造函数中提供笔记本heightweight选项参数,但没有任何更改,也尝试添加

rowconfigure(0, weight=1)
columnconfigure(0, weight=1)

到每个级别的容器(mainframesectionlabelframe),甚至全部到笔记本和树视图(即使AFAIK这只应该是必要的,如果窗口是可以调整大小) - 获得完全相同的结果。

我的理解是,如果小部件放在grid中,而没有任何选项传递给grid(),那么放置的小部件决定需要多少空间{ {1}}管理器将给定列的宽度(或行的高度)容纳到窗口小部件请求的最高值(在给定列或行中管理的所有值)。然后,如果这样的决定空间对于使用相同行/列的其他小部件来说太大,那么它会被拉伸(或者没有 - 主要根据grid选项)。如果这种理解是正确的,那么我不太了解笔记本的行为,特别是因为单独的树视图似乎完全符合它。

我的环境:Ubuntu 17.10,Python 3.6.3,Tkinter 8.6。 如果是treeview列'设置看起来有点奇怪 - 它来自a comment to this question,并且必须像使用水平滚动条一样。

1 个答案:

答案 0 :(得分:1)

问题是您尝试使用grid将滚动条和树视图添加到笔记本中,然后使用笔记本的add方法添加它们。你不能把两者混在一起。创建笔记本时,不应通过packplacegrid直接向其添加小部件。

相反,每个笔记本标签应该是一个框架。然后,您可以使用packplacegrid将任何其他小部件放在该框架内。然后,使用add将此框架添加到笔记本中。

因此,您的第一步是修改build_tree以创建并返回一个框架:

def build_tree(parent):
    frame = ttk.Frame(frame)
    ...
    return frame

接下来,您需要确保树和滚动条是此框架的子项而不是笔记本的子项:

trv = ttk.Treeview(frame)
sbar_vertical = ttk.Scrollbar(frame, ...)
sbar_horizontal = ttk.Scrollbar(frame, ...)

根据经验,每当您使用grid时,您应该始终给予至少一行和一列非零重量​​,以便它们增长和缩小以填充任何额外空间。因此,请确保设置此帧的行和列的权重。

例如:

def build_tree(parent):
    ...
    frame.grid_rowconfigure(0, weight=1)
    frame.grid_columnconfigure(0, weight=1)
    ...

现在,这将使笔记本看起来和笔记本电脑的行为正常。

您对所有其他框架的行/列权重问题类似,因此您希望将权重应用于具有由grid管理的子窗口小部件的每个窗口小部件。