我试图了解tk网格布局是如何工作的,因为界面看起来并不像我想象的那样。我试图在同一行上放置一个标签,后面跟着两个按钮,下一行的树视图跨越标签和按钮的宽度。让它看起来我想要的唯一方法是,如果我在树视图的专栏中使用了一个巨大的值。这是我的代码:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
columnHeadings = ("Heading 1", "Heading 2")
def printMsg():
print("Ok")
frame = ttk.Frame(root).grid(row=0, column=0)
label1 = tk.Label(frame, text="Label here").grid(row=0, column=0, columnspan=1)
button1 = tk.Button(frame, text="Yes", width=2, command=printMsg).grid(row=0, column=1)
button2 = tk.Button(frame, text="No", width=2, command=printMsg).grid(row=0, column=2)
#Label and buttons too far apart
#treeview1 = ttk.Treeview(frame, columns=columnHeadings, show='headings').grid(row=1,column=0, columnspan=3)
#Right distance but that's a huge columnspan
treeview1 = ttk.Treeview(frame, columns=columnHeadings, show='headings').grid(row=1,column=0, columnspan=100)
root.mainloop()
当columnspan为3时,第一行在标签和按钮之间有很多空格。当columnspan为100时,标签和按钮间距看起来要好得多,但我知道这不是正确的方法。这样做的正确方法是什么?
答案 0 :(得分:4)
在这个小程序中,你有几件事要密谋反对你。例如,frame
设置为None
,因此您实际上将所有这些小部件放在根窗口而不是框架中。这是因为x=y().z()
始终将x
设置为z
的结果,grid()
始终返回None
。
其次,grid
的一个好的经验法则是你需要给至少一个(通常是完全一个)行和一个列来获得一个权重,这样tkinter知道如何分配额外的空间。您还需要使用sticky
选项,以便您的窗口小部件展开以填充已经给予它们的空间。你没有使用这些技术。
第三,根据我的经验,我认为当布局语句分散在整个代码中时,调试布局问题非常困难。最好将它们完全分组,这样您就可以更容易地看到您的布局。
grid
您可以通过为列3指定权重为1,然后让树视图跨越该列来解决您的问题。这可以防止按钮所在的列扩展。如果您还解决了frame
为None
的问题,并且使用了相应的sticky
选项,则可以获得所需的效果。
以下是一个例子:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
columnHeadings = ("Heading 1", "Heading 2")
def printMsg():
print("Ok")
frame = tk.Frame(root)
frame.grid(row=0, column=0, sticky="nsew")
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
label1 = tk.Label(frame, text="Label here")
button1 = tk.Button(frame, text="Yes", width=2, command=printMsg)
button2 = tk.Button(frame, text="No", width=2, command=printMsg)
treeview1 = ttk.Treeview(frame, columns=columnHeadings, show='headings')
label1.grid(row=0, column=0, columnspan=1)
button1.grid(row=0, column=1)
button2.grid(row=0, column=2)
treeview1.grid(row=1,column=0, columnspan=4, sticky="nsew")
frame.grid_columnconfigure(3, weight=1)
frame.grid_rowconfigure(1, weight=1)
root.mainloop()
pack
所有这一切,我认为有更好的解决方案,而不是试图让一切都适合网格。我的理念是使用正确的工具来完成工作,在这种情况下,正确的工具是pack
,因为它擅长从上到下或从左到右堆叠(反之亦然)。
在您的情况下,您的程序中有两个不同的区域:顶部的工具栏和下面的树视图。既然你拥有了所有内容,那么使用pack
将一个放在另一个之上是有意义的。所以我首先创建两个框架并打包它们:
toolbar = ttk.Frame(root)
treeframe = ttk.Frame(root)
toolbar.pack(side="top", fill="x")
treeframe.pack(side="bottom", fill="both", expand=True)
现在,您放入toolbar
的任何内容都不会影响treeframe
中的内容,反之亦然。你可以自由地在每个框架中做任何你想做的事情。随着程序的增长,您会发现具有不同区域会使布局问题很多更容易解决。
由于工具栏包含左对齐的按钮,因此您也可以使用pack
。只需确保它们的父项是工具栏框架,您可以像这样打包它们:
label1 = tk.Label(toolbar, ...)
button1 = tk.Button(toolbar, ...)
button2 = tk.Button(toolbar, ...)
label1.pack(side="left")
button1.pack(side="left")
button2.pack(side="left")
最后,如果您只在底部有一个树视图(即:没有滚动条或其他小部件),则可以使用pack
。确保它的父级是treeframe
。如果需要,您可以使用grid
,但pack
更直接。
treeview1.pack(fill="both", expand=True)
关于pack
的好处是你可以把所有东西放在一条线上。你不必采取额外的步骤,给一行或一列重量。
这是一个完整的例子:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
columnHeadings = ("Heading 1", "Heading 2")
def printMsg():
print("Ok")
toolbar = ttk.Frame(root)
treeframe = ttk.Frame(root)
toolbar.pack(side="top", fill="x")
treeframe.pack(side="bottom", fill="both", expand=True)
label1 = tk.Label(toolbar, text="Label here")
button1 = tk.Button(toolbar, text="Yes", width=2, command=printMsg)
button2 = tk.Button(toolbar, text="No", width=2, command=printMsg)
label1.pack(side="left")
button1.pack(side="left")
button2.pack(side="left")
treeview1 = ttk.Treeview(treeframe, columns=columnHeadings, show='headings')
treeview1.pack(side="top", fill="both", expand=True)
root.mainloop()