使用框架和网格的 tkinter gui 布局
tkinter gui layout using frames and grid
我的gui layout
看起来几乎不像 what I expect
所以我假设有一些我不理解的基础知识。
我假设框架包含它们自己的 'grid space'(行、列),但我看到的行为并不能证明这一点,而且我无法让事情按照我想要的方式工作顶部框架。我的标签应该在 L 到 R 的同一行上,在跨越整个框架的 'frame label' 下 - 除了它们没有。我想让实际看起来更像目标jpg,我想用网格来做。
您只能看到绿框右侧的一个输入字段。为什么要去那里?
from Tkinter import *
root = Tk()
root.title('Model Definition')
root.resizable(width=FALSE, height=FALSE)
root.geometry('{}x{}'.format(460, 350))
top_frame = Frame(root, bg='cyan', width = 450, height=50, pady=3).grid(row=0, columnspan=3)
Label(top_frame, text = 'Model Dimensions').grid(row = 0, columnspan = 3)
Label(top_frame, text = 'Width:').grid(row = 1, column = 0)
Label(top_frame, text = 'Length:').grid(row = 1, column = 2)
entry_W = Entry(top_frame).grid(row = 1, column = 1)
entry_L = Entry(top_frame).grid(row = 1, column = 3)
#Label(top_frame, text = '').grid(row = 2, column = 2)
center = Frame(root, bg='gray2', width=50, height=40, padx=3, pady=3).grid(row=1, columnspan=3)
ctr_left = Frame(center, bg='blue', width=100, height=190).grid(column = 0, row = 1, rowspan = 2)
ctr_mid = Frame(center, bg='yellow', width=250, height=190, padx=3, pady=3).grid(column = 1, row=1, rowspan=2)
ctr_right = Frame(center, bg='green', width=100, height=190, padx=3, pady=3).grid(column = 2, row=1, rowspan=2)
btm_frame = Frame(root, bg='white', width = 450, height = 45, pady=3).grid(row = 3, columnspan = 3)
btm_frame2 = Frame(root, bg='lavender', width = 450, height = 60, pady=3).grid(row = 4, columnspan = 3)
root.mainloop()
所以具体来说,我的标签和条目小部件去了哪里,我如何让它们看起来更像目标(顶部框架,其余的稍后使用)。
variable = Widget(...).grid()
将 None
分配给变量,因为 grid()
/pack()
/place()
return None
使用
variable = Widget(...)
variable.grid() # .pack() .place()
I assumed that frames contain their own 'grid space'
这是一个正确的假设。
You can just see one of the entry fields to the right of the green
frame. Why is it going there ?
问题从这里开始:
top_frame = Frame(root, ...).grid(row=0, ...)
在python中,x = y().z()
总是将x
设置为.z()
的结果。在 top_frame = Frame(...).grid(...)
的情况下,grid(...)
总是 returns None
所以 top_frame
将是 None
。这会导致您认为进入顶层框架的每个小部件实际上进入根 window.
解决方案概述
作为一般经验法则,您永远不应在创建小部件的同一语句中调用 grid
、pack
或 place
。部分原因是您正在经历这种确切的行为,但也因为我认为随着时间的推移,这会使您的代码更难编写和维护。
小部件创建和小部件布局是两件不同的事情。根据我的经验,当您将布局命令组合在一起时,布局问题更容易调试。
此外,您在使用 grid
时应该保持一致,并始终按相同的顺序放置选项,这样您可以更轻松地可视化布局。最后,当使用 grid
时,您应该养成始终指定 sticky
选项的习惯,并且始终为每个包含框架中的一行和一列赋予非零权重。
解决方案示例
这是我编写代码的方式。它更长,但更容易理解。
from Tkinter import *
root = Tk()
root.title('Model Definition')
root.geometry('{}x{}'.format(460, 350))
# create all of the main containers
top_frame = Frame(root, bg='cyan', width=450, height=50, pady=3)
center = Frame(root, bg='gray2', width=50, height=40, padx=3, pady=3)
btm_frame = Frame(root, bg='white', width=450, height=45, pady=3)
btm_frame2 = Frame(root, bg='lavender', width=450, height=60, pady=3)
# layout all of the main containers
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(0, weight=1)
top_frame.grid(row=0, sticky="ew")
center.grid(row=1, sticky="nsew")
btm_frame.grid(row=3, sticky="ew")
btm_frame2.grid(row=4, sticky="ew")
# create the widgets for the top frame
model_label = Label(top_frame, text='Model Dimensions')
width_label = Label(top_frame, text='Width:')
length_label = Label(top_frame, text='Length:')
entry_W = Entry(top_frame, background="pink")
entry_L = Entry(top_frame, background="orange")
# layout the widgets in the top frame
model_label.grid(row=0, columnspan=3)
width_label.grid(row=1, column=0)
length_label.grid(row=1, column=2)
entry_W.grid(row=1, column=1)
entry_L.grid(row=1, column=3)
# create the center widgets
center.grid_rowconfigure(0, weight=1)
center.grid_columnconfigure(1, weight=1)
ctr_left = Frame(center, bg='blue', width=100, height=190)
ctr_mid = Frame(center, bg='yellow', width=250, height=190, padx=3, pady=3)
ctr_right = Frame(center, bg='green', width=100, height=190, padx=3, pady=3)
ctr_left.grid(row=0, column=0, sticky="ns")
ctr_mid.grid(row=0, column=1, sticky="nsew")
ctr_right.grid(row=0, column=2, sticky="ns")
root.mainloop()
结果:
我的gui layout
看起来几乎不像 what I expect
所以我假设有一些我不理解的基础知识。
我假设框架包含它们自己的 'grid space'(行、列),但我看到的行为并不能证明这一点,而且我无法让事情按照我想要的方式工作顶部框架。我的标签应该在 L 到 R 的同一行上,在跨越整个框架的 'frame label' 下 - 除了它们没有。我想让实际看起来更像目标jpg,我想用网格来做。
您只能看到绿框右侧的一个输入字段。为什么要去那里?
from Tkinter import *
root = Tk()
root.title('Model Definition')
root.resizable(width=FALSE, height=FALSE)
root.geometry('{}x{}'.format(460, 350))
top_frame = Frame(root, bg='cyan', width = 450, height=50, pady=3).grid(row=0, columnspan=3)
Label(top_frame, text = 'Model Dimensions').grid(row = 0, columnspan = 3)
Label(top_frame, text = 'Width:').grid(row = 1, column = 0)
Label(top_frame, text = 'Length:').grid(row = 1, column = 2)
entry_W = Entry(top_frame).grid(row = 1, column = 1)
entry_L = Entry(top_frame).grid(row = 1, column = 3)
#Label(top_frame, text = '').grid(row = 2, column = 2)
center = Frame(root, bg='gray2', width=50, height=40, padx=3, pady=3).grid(row=1, columnspan=3)
ctr_left = Frame(center, bg='blue', width=100, height=190).grid(column = 0, row = 1, rowspan = 2)
ctr_mid = Frame(center, bg='yellow', width=250, height=190, padx=3, pady=3).grid(column = 1, row=1, rowspan=2)
ctr_right = Frame(center, bg='green', width=100, height=190, padx=3, pady=3).grid(column = 2, row=1, rowspan=2)
btm_frame = Frame(root, bg='white', width = 450, height = 45, pady=3).grid(row = 3, columnspan = 3)
btm_frame2 = Frame(root, bg='lavender', width = 450, height = 60, pady=3).grid(row = 4, columnspan = 3)
root.mainloop()
所以具体来说,我的标签和条目小部件去了哪里,我如何让它们看起来更像目标(顶部框架,其余的稍后使用)。
variable = Widget(...).grid()
将 None
分配给变量,因为 grid()
/pack()
/place()
return None
使用
variable = Widget(...)
variable.grid() # .pack() .place()
I assumed that frames contain their own 'grid space'
这是一个正确的假设。
You can just see one of the entry fields to the right of the green frame. Why is it going there ?
问题从这里开始:
top_frame = Frame(root, ...).grid(row=0, ...)
在python中,x = y().z()
总是将x
设置为.z()
的结果。在 top_frame = Frame(...).grid(...)
的情况下,grid(...)
总是 returns None
所以 top_frame
将是 None
。这会导致您认为进入顶层框架的每个小部件实际上进入根 window.
解决方案概述
作为一般经验法则,您永远不应在创建小部件的同一语句中调用 grid
、pack
或 place
。部分原因是您正在经历这种确切的行为,但也因为我认为随着时间的推移,这会使您的代码更难编写和维护。
小部件创建和小部件布局是两件不同的事情。根据我的经验,当您将布局命令组合在一起时,布局问题更容易调试。
此外,您在使用 grid
时应该保持一致,并始终按相同的顺序放置选项,这样您可以更轻松地可视化布局。最后,当使用 grid
时,您应该养成始终指定 sticky
选项的习惯,并且始终为每个包含框架中的一行和一列赋予非零权重。
解决方案示例
这是我编写代码的方式。它更长,但更容易理解。
from Tkinter import *
root = Tk()
root.title('Model Definition')
root.geometry('{}x{}'.format(460, 350))
# create all of the main containers
top_frame = Frame(root, bg='cyan', width=450, height=50, pady=3)
center = Frame(root, bg='gray2', width=50, height=40, padx=3, pady=3)
btm_frame = Frame(root, bg='white', width=450, height=45, pady=3)
btm_frame2 = Frame(root, bg='lavender', width=450, height=60, pady=3)
# layout all of the main containers
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(0, weight=1)
top_frame.grid(row=0, sticky="ew")
center.grid(row=1, sticky="nsew")
btm_frame.grid(row=3, sticky="ew")
btm_frame2.grid(row=4, sticky="ew")
# create the widgets for the top frame
model_label = Label(top_frame, text='Model Dimensions')
width_label = Label(top_frame, text='Width:')
length_label = Label(top_frame, text='Length:')
entry_W = Entry(top_frame, background="pink")
entry_L = Entry(top_frame, background="orange")
# layout the widgets in the top frame
model_label.grid(row=0, columnspan=3)
width_label.grid(row=1, column=0)
length_label.grid(row=1, column=2)
entry_W.grid(row=1, column=1)
entry_L.grid(row=1, column=3)
# create the center widgets
center.grid_rowconfigure(0, weight=1)
center.grid_columnconfigure(1, weight=1)
ctr_left = Frame(center, bg='blue', width=100, height=190)
ctr_mid = Frame(center, bg='yellow', width=250, height=190, padx=3, pady=3)
ctr_right = Frame(center, bg='green', width=100, height=190, padx=3, pady=3)
ctr_left.grid(row=0, column=0, sticky="ns")
ctr_mid.grid(row=0, column=1, sticky="nsew")
ctr_right.grid(row=0, column=2, sticky="ns")
root.mainloop()