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

dan*_*451 5 python layout tkinter

我正在构建一个软件的GUI,并希望实现这一目标:

######################################
#             |      some title      #
# menu upper  |----------------------#
#             |                      #
#             |         CANVAS       #
# menu lower  |                      #
#             |                      #
#------------------------------------#
#              statusbar             #
######################################
Run Code Online (Sandbox Code Playgroud)

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


不幸的是,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()
Run Code Online (Sandbox Code Playgroud)

这种设计在左侧的菜单中没有内容.每当我添加一些东西self.menu_left_upper或者self.menu_left_lowertest标签一样,我的设计就破了:菜单框架消失了.另外,即使有了柱子,我也不得不删除状态栏,因为当它被添加时,左边的菜单再次消失了.


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

######################################
#             |      some title      #
#             |----------------------#
# menu upper  |                      #
#             |         CANVAS       #
#             |                      #
# menu lower  |                      #
#             |----------------------#
#             |       statusbar      #
######################################
Run Code Online (Sandbox Code Playgroud)

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

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


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

Bry*_*ley 12

做布局的关键是有条不紊,并使用正确的工具来完成工作.这也意味着有时你需要有创意.这意味着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")
Run Code Online (Sandbox Code Playgroud)

无论grid何时使用,您都需要为至少一行和一列提供正权重,以便tkinter知道在哪里使用任何未分配的空间.通常有一个小部件是"主"小部件.在这种情况下,它是画布.您希望确保画布的行和列的权重为1(一):

self.root.grid_rowconfigure(1, weight=1)
self.root.grid_columnconfigure(1, weight=1)
Run Code Online (Sandbox Code Playgroud)

注意:使用pack而不是grid会保存两行代码,因为pack不需要你按照方式设置权重grid.

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

由于您希望每个共享该区域50%的"menu_upper"和"menu_lower",这pack是最简单的解决方案.您可以使用grid,但它需要更多行代码来添加行和列权重.

self.menu_left_upper.pack(side="top", fill="both", expand=True)
self.menu_left_lower.pack(side="top", fill="both", expand=True)
Run Code Online (Sandbox Code Playgroud)

这是一个功能正常的版本,带有状态栏.请注意它在调整窗口大小时的行为方式:

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()
Run Code Online (Sandbox Code Playgroud)

在一个不相关的说明:我强烈建议您不要删除用户调整窗口大小的能力.他们比你更了解他们的要求.如果你使用gridpack不当,图形用户界面将完全重新调整.

  • 多么好的教程。这可能是官方 Tkinter 文档的一部分。 (2认同)