Tkinter网格间距问题

时间:2015-11-12 17:39:00

标签: python tkinter

我试图了解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时,标签和按钮间距看起来要好得多,但我知道这不是正确的方法。这样做的正确方法是什么?

1 个答案:

答案 0 :(得分:4)

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

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

第三,根据我的经验,我认为当布局语句分散在整个代码中时,调试布局问题非常困难。最好将它们完全分组,这样您就可以更容易地看到您的布局。

使用grid

解决问题

您可以通过为列3指定权重为1,然后让树视图跨越该列来解决您的问题。这可以防止按钮所在的列扩展。如果您还解决了frameNone的问题,并且使用了相应的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()