Tkinter 网格间距问题

Alw*_*ng2 4 python tkinter

我试图了解 tk 网格布局是如何工作的,因为界面看起来不像我想象的那样。我试图在同一行上放置一个标签,后跟 2 个按钮,并在下一行放置一个超出标签和按钮宽度的树视图。让它看起来像我想要的唯一方法是如果我为树视图的列跨度使用一个巨大的值。这是我的代码:

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()
Run Code Online (Sandbox Code Playgroud)

当 columnspan 为 3 时,第一行标签和按钮之间有很多空格。当 columnspan 为 100 时,标签和按钮间距看起来好多了,但我知道这不是正确的方法。这样做的正确方法是什么?

Bry*_*ley 6

在这个小程序中,您有几件事情密谋反对您。一方面,frame设置为None,因此您实际上是将所有这些小部件放在根窗口而不是框架中。这是因为x=y().z()始终设置x为 的结果z,并且grid()始终返回None

其次,一个好的经验法则grid是,您需要至少给一个(通常正好是一个)行和一列赋予权重,以便 tkinter 知道如何分配额外的空间。您还需要使用sticky选项,以便您的小部件扩展以填充给它们的空间。您没有使用这些技术。

第三,根据我的经验,当你的布局语句分散在你的代码中时,调试布局问题会变得非常困难。最好将它们一起分组,以便您可以更轻松地可视化您的布局。

解决问题 grid

您可以通过将第 3 列的权重设为 1,然后让您的树视图跨越该列来解决您的问题。这可以防止按钮所在的列扩展。如果您还解决了framebeing的问题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()
Run Code Online (Sandbox Code Playgroud)

另一种解决方案,使用 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)
Run Code Online (Sandbox Code Playgroud)

现在,你放入的任何东西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")
Run Code Online (Sandbox Code Playgroud)

最后,如果您只有底部的树视图(即:没有滚动条或其他小部件),您可以使用pack. 确保它的父级是treeframe. 您可以grid根据需要使用,但pack更直接一些。

treeview1.pack(fill="both", expand=True)
Run Code Online (Sandbox Code Playgroud)

好处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()
Run Code Online (Sandbox Code Playgroud)