Python Tkinter:网格还是网格内的包?
我正在为软件构建GUI,并希望实现以下目标:Python Tkinter:网格还是网格内的包?,python,layout,tkinter,Python,Layout,Tkinter,我正在为软件构建GUI,并希望实现以下目标: ###################################### # | some title # # menu upper |----------------------# # | # # | CANVAS # # menu lower |
######################################
# | some title #
# menu upper |----------------------#
# | #
# | CANVAS #
# menu lower | #
# | #
#------------------------------------#
# statusbar #
######################################
上菜单有一些高级功能,下菜单根据用户输入的不同而变化。Statusbar经常更改其内容
不幸的是,特金特拒绝工作 使用网格布局管理器我无法创建稳定的设计,无法将标签和按钮等内容添加到左侧的菜单中:
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\u left\u upper
或self.menu\u left\u lower
中添加一些内容时,比如测试标签,我的设计就被破坏了:菜单框消失了。
此外,即使使用columnspan,我也必须删除状态栏,因为当添加状态栏时,左侧的菜单再次消失
使用包布局管理器
我得到了以下结果:
######################################
# | some title #
# |----------------------#
# menu upper | #
# | CANVAS #
# | #
# menu lower | #
# |----------------------#
# | statusbar #
######################################
由于我希望左侧的菜单框使用完整的y空间,我使用pack(side=“left”,expand=True,fill=“both”)
使其增长,但此设置始终拒绝状态栏的全宽
此外,纯包管理器代码看起来“丑陋”。我认为使用网格管理器的设计更“清晰”。因此,我认为网格布局或网格布局内的包布局会很好
有人能帮忙吗?我被困在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)
在菜单左上方
框架和菜单左上方.mainloop()之间
其作用如下:
默认情况下,容器小部件会展开或折叠到刚好可以容纳其内容的大小。因此,当您调用pack时,它会导致帧收缩。此功能称为几何体传播
对于绝大多数应用程序,这是您想要的行为。对于那些很少需要显式设置容器大小的情况,可以关闭此功能。要关闭它,请在容器上调用pack\u propagate
或grid\u 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()
那你的计划就行了。
希望有帮助:)
还有,为什么所有的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()
布局的关键在于有条不紊,并使用正确的工具
为了这份工作。这也意味着有时候你需要有创造力。
这意味着在一个网格中布局时使用网格
网格
,在从上到下或
从左到右
另一个关键是将布局代码分组在一起。很多很多
当布局都在一个块中时,更易于可视化和修改布局
代码的定义
在您的情况下,您似乎有三个或四个不同的区域,这取决于
看你怎么算。如果要使用网格
,最容易
将“菜单上部”和“菜单下部”组合成一个框架,并处理该框架
整个框架作为一个表格单元。看起来你已经这么做了,
这很好
那么,让我们从这些主要领域开始:
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")
无论何时使用网格
,都需要至少给出一行和一行
列一个正权重,以便tkinter知道在哪里使用任何
未分配的空间。通常有一个小部件是“主”
小装置。在这种情况下,它是画布。你想确保
画布的行和列的权重为1(一):
注意:使用pack
而不是grid
将为您节省两行代码,因为pack
不需要您像grid
那样设置权重
接下来,我们需要解决菜单区域的问题。默认情况下,
框架收缩以适应其内容,这就是添加标签的原因
破坏了你的布局。你没有告诉tkinter如何处理额外的空间,所以框架缩小到合适的位置,多余的空间就没有用了
因为您希望“菜单上方”和“菜单下方”
每个共享50%的面积,pack
是最简单的解决方案。你可以
使用网格
,但它需要更多的代码行来添加行和列的权重
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()
另外,我强烈建议您不要删除用户调整窗口大小的功能。他们比你更清楚他们的要求是什么。如果正确使用grid
和pack
,GUI将完全调整大小 是的,但它并没有解决一个奇怪的错误,即当我在左侧添加内容时,左侧的菜单栏消失了。如果我这样做self.test=tk.Label(self.menu_left_upper,text=“test”)
和self.test.pack()
或self.test.grid()
左侧的菜单上/下消失。您是否尝试给self.test
一些填充(padx
和pady
),为什么会投反对票?有点困惑为什么有人会这么做。。。回答问题并获得计划:(谢谢,将对此进行测试。否决票不是我。因此,使用grid manager在顶层构建框架并管理它们,而使用pack manager管理框架的内容,是合法的吗?我尝试了.grid\u propagate(False)的所有可能组合
:仅将其分配给菜单左
,仅分配给菜单左
上
,仅分配给菜单左
下
或其组合。均未起作用。菜单和子帧正确显示,没有内容,但只要将测试
标签添加到菜单左
上上,帧就会消失。Fo格式化是垃圾。请参见编辑。您需要将其放在菜单左起之前
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()