简体   繁体   English

Tkinter网格间距问题

[英]Tkinter grid spacing problems

I'm trying to understand how tk grid layouts work since the interface isn't looking the way I thought it would. 我试图了解tk网格布局是如何工作的,因为界面看起来不像我想象的那样。 I'm trying to place a label followed by 2 buttons on the same row, and a treeview on the next row that spans beyond the width of the label and buttons. 我正在尝试在同一行上放置一个标签,后跟两个按钮,并在下一行上放置超出标签宽度和按钮的树视图。 The only way to get this to look how I want is if I use a huge value for the treeview's columnspan. 让它看起来我想要的唯一方法是,如果我为treeview的columnspan使用一个巨大的值。 Here is my code: 这是我的代码:

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

When columnspan is 3, the first row has a lot of spaces between the label and buttons. 当columnspan为3时,第一行在标签和按钮之间有很多空格。 When columnspan is 100, the label and button spacing looks a lot better but I know this isn't the correct way. 当columnspan为100时,标签和按钮间距看起来好多了,但我知道这不是正确的方法。 What's the correct way to do this? 这样做的正确方法是什么?

You have several things conspiring against you in this little program. 在这个小程序中,你有几件事情密谋反对你。 For one, frame is set to None , so you are actually putting all these widgets in the root window rather than the frame. 例如, frame设置为None ,因此您实际上将所有这些小部件放在根窗口而不是框架中。 This is because x=y().z() always sets x to the result of z , and grid() always returns None . 这是因为x=y().z()总是将x设置为z的结果,而grid()总是返回None

Second, a good rule of thumb for grid is that you need to give at least one (and usually exactly one) row and one column to have a weight, so that tkinter knows how to allocate extra space. 其次, grid一个好的经验法则是你需要给至少一个(通常只有一个)行和一个列来获得权重,以便tkinter知道如何分配额外的空间。 You also need to use the sticky option so that your widgets expand to fill the space that's been given them. 您还需要使用sticky选项,以便您的窗口小部件展开以填充已为其提供的空间。 You are using neither of these techniques. 您没有使用这些技术。

Third, in my experience I think it makes it very hard to debug layout problems when your layout statements are scattered throughout your code. 第三,根据我的经验,我认为当布局语句分散在整个代码中时,调试布局问题非常困难。 It's best to group them altogether so you can more easily visualize your layout. 最好将它们完全分组,以便您可以更轻松地查看布局。

Solving the problem with grid grid解决问题

You can solve your problem by giving column 3 a weight of 1, and then having your treeview span that column. 您可以通过为列3指定权重为1,然后让树视图跨越该列来解决您的问题。 This prevents the columns that your buttons are in from expanding. 这可以防止按钮所在的列扩展。 If you also fix the problem with frame being None , and if you use the appropriate sticky options, you can get the look you want. 如果您还修复了frameNone的问题,并且如果使用适当的sticky选项,则可以获得所需的外观。

Here's an example: 这是一个例子:

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

An alternate solution, using pack 另一种解决方案,使用pack

All that being said, I think there are better solutions than to try to get everything to fit in a grid. 所有这一切,我认为有更好的解决方案,而不是试图让一切都适合网格。 My philosophy is to use the right tool for the job, and in this case the right tool is pack because it excels at stacking things top-to-bottom OR left-to-right (and visa versa). 我的理念是使用正确的工具,在这种情况下,正确的工具是pack因为它擅长从上到下或从左到右堆叠的东西(反之亦然)。

In your case, you have two distinct regions in your program: a toolbar across the top, and a treeview down below. 在您的情况下,您的程序中有两个不同的区域:顶部的工具栏和下面的树视图。 Since that's all you have, it makes sense to use pack , to place one on top of the other. 既然这就是你所拥有的,那么使用pack ,将一个放在另一个上面是有意义的。 So I would start by creating two frames and packing them: 所以我首先创建两个框架并打包它们:

toolbar = ttk.Frame(root)
treeframe = ttk.Frame(root)

toolbar.pack(side="top", fill="x")
treeframe.pack(side="bottom", fill="both", expand=True)

Now, anything you put in toolbar will not affect things in treeframe and visa versa. 现在,您放在toolbar任何内容都不会影响treeframe ,反之亦然。 You are free to do whatever you want in each of those frames. 你可以自由地在每个框架中做任何你想做的事情。 As your program grows, you'll find that having distinct regions makes layout problems much easier to solve. 随着程序的增长,你会发现拥有不同的区域会使布局问题容易解决。

Since the toolbar contains buttons that are left-justified, you can use pack there too. 由于工具栏包含左对齐的按钮,因此您也可以使用pack Just make sure their parent is the toolbar frame, and you can pack them like this: 只需确保它们的父项是工具栏框架,您可以像这样打包它们:

label1 = tk.Label(toolbar, ...)
button1 = tk.Button(toolbar, ...)
button2 = tk.Button(toolbar, ...)

label1.pack(side="left")
button1.pack(side="left")
button2.pack(side="left")

Finally, if you only have a treeview in the bottom (ie: no scrollbars or other widgets), you can use pack . 最后,如果您只在底部有一个树视图(即:没有滚动条或其他小部件),您可以使用pack Make sure it's parent is treeframe . 确保它的父级是treeframe You can use grid if you want, but pack is a bit more straight-forward. 如果需要,您可以使用grid ,但pack更直接。

treeview1.pack(fill="both", expand=True)

The nice thing about pack is you can truly put everything on one line. 关于pack是你可以真正把所有东西放在一条线上。 You don't have to take the extra step and give a row or column a weight. 您不必采取额外步骤,并给行或列一个权重。

Here's a complete example: 这是一个完整的例子:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM