Tkinter:网格或网格内的包?

新手上路,请多包涵

我正在为软件构建 GUI 并希望实现此目的:

 ######################################
#             |      some title      #
# menu upper  |----------------------#
#             |                      #
#             |         CANVAS       #
# menu lower  |                      #
#             |                      #
#------------------------------------#
#              statusbar             #
######################################

上层菜单 具有一些高级功能, 下层菜单 根据用户输入而变化。状态栏经常更改其内容。


不幸的是,Tkinter 拒绝工作。

使用 网格布局管理器,我无法创建稳定的设计并向左侧菜单添加标签和按钮等内容:

 self.root = tk.Tk()
self.root.resizable(width=0, height=0)
self.root.title("some application")

# menu left
self.menu_left = tk.Frame(self.root, width=150, bg="#ababab")
self.menu_left.grid(row=0, column=0, rowspan=2, sticky="ns")

self.menu_left_upper = tk.Frame(self.menu_left, width=150, height=150, bg="red")
self.menu_left_upper.grid(row=0, column=0)

# this label breaks the design
#self.test = tk.Label(self.menu_left_upper, text="test")
#self.test.pack()

self.menu_left_lower = tk.Frame(self.menu_left, width=150, bg="blue")
self.menu_left_lower.grid(row=1, column=0)

# right area
self.some_title_frame = tk.Frame(self.root, bg="#dfdfdf")
self.some_title_frame.grid(row=0, column=1, sticky="we")

self.some_title = tk.Label(self.some_title_frame, text="some title", bg="#dfdfdf")
self.some_title.pack()

self.canvas_area = tk.Canvas(self.root, width=500, height=400, background="#ffffff")
self.canvas_area.grid(row=1, column=1)

self.root.mainloop()

此设计 在左侧菜单中没有内容的情况下工作。每当我在 self.menu_left_upperself.menu_left_lower 添加一些东西时,比如 test 标签,我的设计就坏了:菜单框架消失了。此外,即使使用 columnspan ,我也必须删除状态栏,因为当添加它时,左侧的菜单再次消失。


使用 包布局管理器 我得到了这个:

 ######################################
#             |      some title      #
#             |----------------------#
# menu upper  |                      #
#             |         CANVAS       #
#             |                      #
# menu lower  |                      #
#             |----------------------#
#             |       statusbar      #
######################################

由于我希望左侧的菜单框架占用完整的 y 空间,因此我使用 pack(side="left", expand=True, fill="both") 使其增长,但此设置始终拒绝状态栏达到全宽。

此外,纯包管理器代码看起来“丑陋” 。我认为带有网格管理器的设计“更清晰”。因此我认为 网格布局或网格布局内的包布局会很好 吗?


谁能帮忙?我陷入了 GUI 地狱:/

原文由 daniel451 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 709
2 个回答

进行布局的关键是要有条不紊,并使用正确的工具来完成工作。这也意味着有时您需要发挥创造力。这意味着在 grid 中布局时使用 grid pack ,在从上到下或从左到右布局时使用 --- 。

另一个关键是将布局代码组合在一起。当所有内容都在一个代码块中时,可视化和修改布局要容易得多。

在您的情况下,您似乎有三个或四个不同的区域,具体取决于您的计数方式。如果您想使用 grid ,最简单的方法是将“菜单上部”和“菜单下部”组合成一个框架,并将整个框架视为一个表格单元格。看起来你已经在这样做了,这很好。

那么,让我们从这些主要领域开始:

 self.menu_left.grid(row=0, column=0, rowspan=2, sticky="nsew")
self.some_title_frame.grid(row=0, column=1, sticky="ew")
self.canvas_area.grid(row=1, column=1, sticky="nsew")
# you don't have a status bar in the example code, but if you
# did, this is where you would put it
# self.status_frame.grid(row=2, column=0, columnspan=2, sticky="ew")

任何时候你使用 grid ,你需要至少给一行和一列一个正权重,这样 tkinter 就知道在哪里使用任何未分配的空间。通常有一个小部件是“主要”小部件。在这种情况下,它是画布。您要确保画布的行和列的权重为 1(一):

 self.root.grid_rowconfigure(1, weight=1)
self.root.grid_columnconfigure(1, weight=1)

note: using pack instead of grid would save you two lines of code, since pack doesn’t require you to set weights the way grid 确实如此。

接下来,我们需要解决菜单区域的问题。默认情况下,框架会缩小以适合其内容,这就是添加标签会破坏布局的原因。你没有告诉 tkinter 如何处理额外的空间,因此框架缩小以适合,额外的空间未被使用。

由于您希望“menu_upper”和“menu_lower”各占该区域的 50%, pack 是最简单的解决方案。您可以使用 grid ,但它需要更多代码行来添加行和列权重。

 self.menu_left_upper.pack(side="top", fill="both", expand=True)
self.menu_left_lower.pack(side="top", fill="both", expand=True)

这是一个功能版本,带有状态栏。请注意当您调整窗口大小时它的行为与应有的完全一致:

 import Tkinter as tk

class Example():
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("some application")

        # menu left
        self.menu_left = tk.Frame(self.root, width=150, bg="#ababab")
        self.menu_left_upper = tk.Frame(self.menu_left, width=150, height=150, bg="red")
        self.menu_left_lower = tk.Frame(self.menu_left, width=150, bg="blue")

        self.test = tk.Label(self.menu_left_upper, text="test")
        self.test.pack()

        self.menu_left_upper.pack(side="top", fill="both", expand=True)
        self.menu_left_lower.pack(side="top", fill="both", expand=True)

        # right area
        self.some_title_frame = tk.Frame(self.root, bg="#dfdfdf")

        self.some_title = tk.Label(self.some_title_frame, text="some title", bg="#dfdfdf")
        self.some_title.pack()

        self.canvas_area = tk.Canvas(self.root, width=500, height=400, background="#ffffff")
        self.canvas_area.grid(row=1, column=1)

        # status bar
        self.status_frame = tk.Frame(self.root)
        self.status = tk.Label(self.status_frame, text="this is the status bar")
        self.status.pack(fill="both", expand=True)

        self.menu_left.grid(row=0, column=0, rowspan=2, sticky="nsew")
        self.some_title_frame.grid(row=0, column=1, sticky="ew")
        self.canvas_area.grid(row=1, column=1, sticky="nsew")
        self.status_frame.grid(row=2, column=0, columnspan=2, sticky="ew")

        self.root.grid_rowconfigure(1, weight=1)
        self.root.grid_columnconfigure(1, weight=1)

        self.root.mainloop()

Example()


与此无关:我强烈建议您 不要 删除用户调整窗口大小的功能。他们比你更清楚他们的要求是什么。如果您正确使用 gridpack ,GUI将完美调整大小。

原文由 Bryan Oakley 发布,翻译遵循 CC BY-SA 4.0 许可协议

通过放入行:

 menu_left_upper.grid_propagate(False)

在你的 menu_left_upper 框架和 menu_left_upper.mainloop() 之间

这作为:

默认情况下,容器小部件会展开或折叠到刚好足以容纳其内容的大小。因此,当您调用 pack 时,它会导致框架缩小。此功能称为 _几何传播_。

对于绝大多数应用程序,这是您想要的行为。在极少数情况下,当您想要明确设置容器的大小时,您可以关闭此功能。要关闭它,请在容器上调用 pack_propagategrid_propagate (取决于您是在该容器上使用网格还是包装),给它一个值 False

请参阅指向另一个问题的链接

要获得状态栏,只需实现另一个框架和网格方法:

 status_bar_frame = Frame(root, bg="#dfdfdf")
status_bar_frame.grid(row=3, column=0, columnspan=2, sticky="we")

status_bar = Label(status_bar_frame, text="status bar", bg="#dfdfdf")
status_bar.pack()

然后你的计划奏效了。希望能帮助到你 :)

附言。还有为什么所有 self 属性?

编辑:工作你需要做的:

 menu_left_upper = Frame(menu_left, width=225, height=225, bg="red")
menu_left_upper.grid_propagate(False)
menu_left_upper.grid(row=0, column=0)

# this label breaks the design
test = Label(menu_left_upper, text="test", bg='red')
test.grid()

我的结果

原文由 Benno_S 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏