Tkinter:网格还是网格内的包? [英] Tkinter: grid or pack inside a grid?

查看:24
本文介绍了Tkinter:网格还是网格内的包?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am building a GUI for a software and want to achieve this:

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

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

Menu upper has some high level functionality, menu lower is changing in dependency of user input. Statusbar changes its contents often.

不幸的是,Tkinter 拒绝工作.

Unfortunately, Tkinter refuses to work.

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

Using the grid layout manager I were unable to create a stable design and adding content like labels and buttons to the menu on the left side:

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,我也不得不删除状态栏,因为添加状态栏后,左侧的菜单又消失了.

This design worked without contents in the menu on the left side. Whenever I added something in self.menu_left_upper or self.menu_left_lower, like the test label, my design got broke: the menu frames disappeared. Additionally, even with columnspan, I had to remove the statusbar, because when it was added the menus on the left disappeared, again.

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

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

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

Since I wanted the menu frame on the left to consume the full y-space I made it grow with pack(side="left", expand=True, fill="both"), but this setup always denies the statusbar to go for the full width.

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

Besides, the pure pack manager code looks "ugly". I think a design with a grid manager is "clearer". Therefore I thought a grid or a pack layout inside a grid layout would be nice?

有人可以帮忙吗?我被困在 GUI 地狱中:/

Can anyone help? I am stuck in the GUI-hell :/

推荐答案

布局的关键是要有条不紊,并使用正确的工具为了工作.这也意味着有时您需要发挥创造力.这意味着在布局时使用 gridgrid,并使用 pack 从上到下或左到右.

The key to doing layout is to be methodical, and to use the right tool for the job. It also means that sometimes you need to be creative. That means using grid when laying things out in a grid, and using pack when laying things out top-to-bottom or left-to-right.

另一个关键是将您的布局代码组合在一起.很多很多当布局都在一个块中时,更容易可视化和修改布局代码.

The other key is to group your layout code together. It's much, much easier to visualize and modify the layout when it's all in one block of code.

在您的情况下,您似乎有三到四个不同的区域,具体取决于看你怎么算.如果你想使用 grid,最简单的方法是将上菜单"和下菜单"组合成一个框架,然后处理整个框架作为表格单元格.看起来你已经在这样做了,哪个好.

In your case you seem to have three or four distinct areas, depending on how you count. If you want to use grid, it will be easiest to combine "menu upper" and "menu lower" into a frame, and treat that whole frame as a table cell. It looks like you're already doing that, which is good.

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

So, let's start with those main areas:

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(一):

Any time you use grid, you need to give at least one row and one column a positive weight so that tkinter knows where to use any unallocated space. Usually there is one widget that is the "main" widget. In this case it's the canvas. You want to make sure that the row and column for the canvas has a weight of 1 (one):

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

注意:使用 pack 而不是 grid 将为您节省两行代码,因为 pack 不需要您设置权重grid 的方式.

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 does.

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

Next, we need to solve the problem of the menu areas. By default, frames shrink to fit their contents, which is why adding the label broke your layout. You weren't telling tkinter what to do with extra space, so the frames shrunk to fit, and extra space went unused.

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

Since you want "menu_upper" and "menu_lower" to each share 50% of that area, pack is the simplest solution. You can use grid, but it requires more lines of code to add the row and column weights.

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

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

Here is a functioning version, with statusbar. Notice how it behaves exactly as it should when you resize the window:

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 将完美地调整大小.


On an unrelated note: I would strongly encourage you to not remove the ability for the user to resize the window. They know better than you what their requirements are. If you use grid and pack properly, the GUI will resize perfectly.

这篇关于Tkinter:网格还是网格内的包?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆