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

2024-04-01

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

在我的研究中,我遇到了使用 Sticky、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()

~~Update~~

我尝试了以下方法,但没有成功:

    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)

你需要使用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)

接下来,您将获得“角落”标签。同样,由于容器只是一行小部件,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除了将小部件放入其容器中之外,您还必须注意为各个列和行赋予“权重”,以便它们正确调整大小。当您只是将小部件堆叠在一起或将它们排列成一行时,pack使用起来更加方便。

在我的 GUI 中,我几乎总是结合使用grid and pack。他们都很强大,并且擅长不同的事情。唯一要记住的是——这是至关重要的-- 是你不能在同一个父级中使用它们。以您的代码为例,您不能使用pack对于 top_left 框架和grid对于 top_right 框架,因为它们共享相同的父级。你can但是,请在同一应用程序中混合使用它们。

再次,使用网格

好吧,也许你真的想用grid:也许这是一项学校作业,或者也许您只想一次专注于一个几何管理器。这很酷。我就是这样做的。再次强调,你必须分而治之:

从主框架开始。将我们打包主容器的一条语句替换为以下几行。请注意,我们必须配置行和列parent,而不是我们创建的框架。

    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陈述如下,密切注意给予“权重”的内容:

    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使用起来更容易一些,因为您不必担心行和列的权重。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Tkinter Grid:如何定位小部件以使它们不会粘在一起 的相关文章

随机推荐