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

查看:91
本文介绍了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 :/

推荐答案

进行布局的关键是要有条理,并使用正确的工具 为了工作.这也意味着有时您需要发挥创造力. 这意味着在将内容放置在 grid,并在从上到下进行布局时使用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天全站免登陆