Tkinter Grid:如何定位小部件,使它们不会粘在一起

时间:2013-02-18 23:07:43

标签: python tkinter

我正在尝试创建两个Label小部件,这些小部件位于我的测试用户界面的左上角和右上角。问题是小部件被粘在一起,我希望它们之间有空间。

在我的研究中,我遇到了使用粘性,padx和pady选项的建议。但无论我传递给.grid()的参数是什么,我似乎都无法在我的小部件之间创建空间。我知道无论两个小部件之间的列和行数是多少,如果所说的行/列都是空的,那么就好像它们不存在并且小部件看起来粘在一起。

使用.grid()方法,如何定位小部件以使它们不会粘在一起?

到目前为止,这是我的代码:

#!/usr/bin/python
from Tkinter import *

class MyApp:
    def __init__(self, parent):
        self.myParent = parent
        self.main_container = Frame(parent)
        self.main_container.grid(row=0, rowspan=2, column=0, columnspan=4)

        self.top_frame = Frame(self.main_container)
        self.top_frame.grid(row=0, column=0, columnspan=4)

        self.top_left = Frame(self.top_frame)
        self.top_left.grid(row=0, column=0, columnspan=2)

        self.top_right = Frame(self.top_frame)
        self.top_right.grid(row=0, column=2, columnspan=2)

        self.bottom_frame = Frame(self.main_container)
        self.bottom_frame.grid(row=2, column=0, columnspan=4)

        self.top_left_label = Label(self.top_left, text="Top Left")
        self.top_left_label.grid(row=0, column=0, sticky='W', padx=2, pady=2)

        self.top_right_label = Label(self.top_right, text="Top Right")
        self.top_right_label.grid(row=0, column=4, sticky='E', padx=2, pady=2)

        self.text_box = Text(self.bottom_frame, height=5, width=40)
        self.text_box.grid(row=0, column=0)

root = Tk()
root.title("Test UI")
myapp = MyApp(root)
root.mainloop()

〜更新〜

我尝试了以下但是没有用:

    self.top_left = Frame(self.top_frame)
    self.top_left.grid(row=0, column=0, columnspan=2)
    for c in range(2):
        self.top_left.columnconfigure(c, weight=2)

    self.top_right = Frame(self.top_frame)
    self.top_right.grid(row=0, column=2, columnspan=2)
    for c in range(2):
        self.top_right.columnconfigure(c, weight=2)

5 个答案:

答案 0 :(得分:65)

您需要使用grid_columnconfigure为中间的列提供一些权重。与其他色谱柱相比,它们的重量更大,它们可以扩展和收缩,以填充您拥有的任何额外空间。但是,在您的情况下,确实不需要使用网格。 GUI中的所有内容都沿着特定边对齐,pack更适合自然。

我将展示如何使用pack和grid,从pack开始,因为它是最简单的。即使您坚持使用grid,也请仔细阅读下一节,了解如何将一个大的布局问题分解为许多较小的布局问题。

分而治之

在Tkinter中进行布局的最佳方法是分享和征服"。从最外面的小部件开始,按照您想要的方式获取它们。然后,一次解决这些问题。

在您的情况下,您有一个最外面的小部件 - 主容器。由于它是窗口中唯一的小部件,因此pack是最简单的方法来填充整个容器。您也可以使用网格,但它需要一些额外的工作:

self.main_container = Frame(parent. background="bisque")
self.main_container.pack(side="top", fill="both", expand=True)

暂时为您的相框提供独特的色彩,以便您在开发时可视化它们。只需将上述代码添加到__init__,运行您的应用,然后调整窗口大小以确定主框架是否正确增长和缩小。

接下来,您有两个框架 - top_frame和bottom_frame。通过他们的名字和你如何尝试使用网格来判断,我认为他们应该在x方向填充GUI。此外,我猜测顶部框架是某种工具栏,底部框架是真正的"主要" GUI的一部分。因此,让底部小部件占用所有额外空间。

由于它们彼此叠加,pack再次成为自然选择。添加以下代码 - 仅以下代码 - 以确保这些区域占用您期望的窗口部分,并且它们具有适当的调整大小行为。

    self.top_frame = Frame(self.main_container, background="green")
    self.bottom_frame = Frame(self.main_container, background="yellow")
    self.top_frame.pack(side="top", fill="x", expand=False)
    self.bottom_frame.pack(side="bottom", fill="both", expand=True)

接下来是标签的框架。同样,这些占据了容器边缘的空间,因此pack最有意义。再次,只需添加以下代码,运行您的程序,并确保仍然正确调整大小并填充窗口的正确部分:

    self.top_left = Frame(self.top_frame, background="pink")
    self.top_right = Frame(self.top_frame, background="blue")
    self.top_left.pack(side="left", fill="x", expand=True)
    self.top_right.pack(side="right", fill="x", expand=True)

接下来,你有#34;角落"标签。同样,由于容器只是一行小部件,pack使其变得简单。由于您希望角落中的标签,我们将sticky属性设置为每个属性略有不同:

    self.top_left_label = Label(self.top_left, text="Top Left")
    self.top_right_label = Label(self.top_right, text="Top Right")
    self.top_left_label.pack(side="left")
    self.top_right_label.pack(side="right")

最后,您有文本小部件。它填满整个底部框架,所以pack再次成为我们的朋友:

    self.text_box = Text(self.bottom_frame, height=5, width=40, background="gray")
    self.text_box.pack(side="top", fill="both", expand=True)

包或网格?

您使用网格作为原始代码并询问如何修复它。为什么我在我的例子中使用pack?

使用pack时,所有配置选项都可以在一次调用中完成。使用grid并将小部件放入容器中时,您还必须注意提供各种列和行" weight"这样他们就可以正常调整大小。当您只是将小部件堆叠在一起或将它们排成一行时,pack更容易使用。

在我的GUI中,我几乎总是使用gridpack的组合。它们既强大又擅长于不同的事物。唯一要记住的是 - ,这是至关重要的 - 是你不能在同一个父母中使用它们。以您的代码为例,您不能将pack用于top_left框架而grid用于top_right框架,因为它们都共享同一个父框架。但 可以在同一个应用程序中混合它们。

再次使用网格

好吧,也许你真的想要使用grid:也许这是一个学校作业,或者你可能只想一次关注一个几何管理器。太酷了。这是我将如何做到的。再一次,你必须分而治之:

从主框架开始。用以下行替换我们打包主容器的一个语句。请注意,我们必须在上配置行和列,而不是我们创建的帧。

    self.main_container.grid(row=0, column=0, sticky="nsew")
    self.myParent.grid_rowconfigure(0, weight=1)
    self.myParent.grid_columnconfigure(0, weight=1)

好的,现在是顶部和底部的框架。删除pack,然后添加以下行。您仍然只有一列,但这次有几行。注意哪一行的权重为1:

    self.top_frame.grid(row=0, column=0, sticky="ew")
    self.bottom_frame.grid(row=1, column=0,sticky="nsew")
    self.main_container.grid_rowconfigure(1, weight=1)
    self.main_container.grid_columnconfigure(0, weight=1)

角落框架 - 最后,一个有多个列的容器!让我们在中间创建第三列以消除所有松弛。将pack语句替换为以下内容,密切关注所给出的内容" weight":

    self.top_left.grid(row=0, column=0, sticky="w")
    self.top_right.grid(row=0, column=2, sticky="e")
    self.top_frame.grid_columnconfigure(1, weight=1)

接下来,他们的框架中的标签。由于我们不需要它们进行扩展,因此我们可以将默认权重保持为零。您可能认为两个标签都在列零中很奇怪。请记住,他们在不同的父母,他们是他们父母唯一的小部件,所以每个只有一列:

    self.top_left_label.grid(row=0, column=0, sticky="w")
    self.top_right_label.grid(row=0, column=0, sticky="e")

最后,我们有了文本小部件,它是底部框架中唯一的小部件。用以下内容替换最终的pack语句:

    self.text_box.grid(row=0, column=0, sticky="nsew")
    self.bottom_frame.grid_rowconfigure(0, weight=1)
    self.bottom_frame.grid_columnconfigure(0, weight=1)

结论

布置小部件很容易,但你必须系统化。想想你在做什么,将你的小部件组织成小组,然后一次一个地处理这些小组。当您这样做时,应该明白应该使用哪个几何管理器。

正如您所看到的,grid需要更多代码行,但当您确实拥有网格时,它是正确的选择。在您的情况下,您已经将GUI细分为多个部分,因此即使最终结果是网格,每个部分也可以打包在顶部或下面,也可以打包到左边或右边。在这些情况下,pack更容易使用,因为您不必担心行和列权重。

答案 1 :(得分:1)

如果您向bg = "red"top_left个构建器添加top_right,您会看到Frames如何卡在中心,即使使用sticky选项。如果它们不包含除单个小部件之外的任何内容,我建议不要使用它们。

#!/usr/bin/python
from Tkinter import *

class MyApp:
    def __init__(self, parent):
        self.top_left_label = Label(parent, text="Top Left")
        self.top_left_label.grid(row=0, column=0, padx=2, pady=2, sticky=N+S+W)

        self.top_right_label = Label(parent, text="Top Right")
        self.top_right_label.grid(row=0, column=1, padx=2, pady=2, sticky=N+S+E)

        self.text_box = Text(parent, height=5, width=40)
        self.text_box.grid(row=1, column=0, columnspan=2)

root = Tk()
root.title("Test UI")
myapp = MyApp(root)
root.mainloop()

答案 2 :(得分:1)

这是一种简单的方法:

  • 首先在纸上设计你的gui或使用任何适合你的工具
  • 使用网格布局管理器
  • 无论您想要创建空白区域,请使用columnspan或rowspan 布局的属性,粘性的组合 columnspan或rowspan允许您将一个以上的网格单元格分配给gui组件,而使用sticky属性可以强制该元素粘贴到一侧并在另一侧留下空白区域

答案 3 :(得分:1)

迟到总比没有好;)

Tkinter的“网格”想把所有东西放在一起。这就是为什么你不能跳过细胞。您必须指定宽度,然后锚定文本。我添加了颜色来帮助展示细胞。我把bd放在框架中。然后我必须给左右两侧的细胞赋予宽度,这样网格就会给它们带来重量。然后锚文本西或东。我不知道为什么我必须为每个单元格添加额外的2个空格,但我认为这是一个字体问题。

我相信Rodas更清洁,更简单,但我试图保持在您询问的参数范围内。

对于小东西来说,包装更容易,更快。

from tkinter import *

class MyApp:
    def __init__(self, parent):
        self.myParent = parent

        self.main_container = Frame(parent, bg="green")
        self.main_container.grid()

        self.top_frame = Frame(self.main_container)
        self.top_frame.grid()

        self.top_left = Frame(self.top_frame, bd=2)
        self.top_left.grid(row=0, column=0)

        self.top_right = Frame(self.top_frame, bd=2)
        self.top_right.grid(row=0, column=2)

        self.top_left_label = Label(self.top_left, bd=2, bg="red", text="Top Left", width=22, anchor=W)
        self.top_left_label.grid(row=0, column=0)

        self.top_right_label = Label(self.top_right, bd=2, bg="blue", text="Top Right", width=22, anchor=E)
        self.top_right_label.grid(row=0, column=0)

        self.bottom_frame = Frame(self.main_container, bd=2)
        self.bottom_frame.grid(row=2, column=0)

        self.text_box = Text(self.bottom_frame, width=40, height=5)
        self.text_box.grid(row=0, column=0)

root = Tk()
root.title("Test UI")
myapp = MyApp(root)
root.mainloop()

答案 4 :(得分:0)

如果您需要完全控制gui组件的位置,请尝试布局;一种高度可管理的方法是在几个框架中组织您的组件,每个框架都有网格或包布局,然后使用场所布局组织所有这些框架。