繁体   English   中英

Tkinter:网格内的网格或包装?

[英]Tkinter: grid or pack inside a grid?

我正在构建一个软件的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标签一样,我的设计破了:菜单框架消失了。 另外,即使有了柱子 ,我也不得不删除状态栏,因为当它被添加时,左边的菜单再次消失了。


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

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

因为我希望左边的菜单框架消耗完整的y空间,所以我使用它来增长pack(side="left", expand=True, fill="both") ,但是这个设置总是拒绝状态栏去全宽。

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


有人可以帮忙吗? 我陷入了GUI-hell:/

做布局的关键是有条不紊,并使用正确的工具来完成工作。 这也意味着有时你需要有创意。 这意味着在grid放置东西时使用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)

注意:使用pack代替grid可以节省两行代码,因为pack不需要像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将完美调整大小。

self.root.mainloop()之前添加以下代码可以实现您正在寻找的内容

self.some_status = tk.Label(self.root, text="status bar", bg="#dfdfdf")
self.some_status.grid(row=3, column=0, columnspan=2, sticky="we")

通过加入:

menu_left_upper.grid_propagate(False) 

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

这适用于:

默认情况下,容器窗口小部件会扩展或折叠,以便足以容纳其内容。 因此,当您调用pack时,会导致帧缩小。 此功能称为几何体传播

对于绝大多数应用程序,这是您想要的行为。 对于那些您想要明确设置容器大小的罕见情况,您可以关闭此功能。 要关闭它,请在容器上调用pack_propagategrid_propagate (取决于您是否在该容器上使用grid或pack),将其赋值为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()

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

PS。 还有为什么所有的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()

我的结果

暂无
暂无

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

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