Python 使用框架和网格的 tkinter gui 布局

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34276663/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 14:44:08  来源:igfitidea点击:

tkinter gui layout using frames and grid

pythonlayouttkinterframe

提问by shawn

My gui layout

我的gui布局

gui layout

gui布局

looks almost nothing like what I expect

看起来几乎不像我期望的那样

what I expect

我期待什么

so I assume there are some basics that I don't understand.

所以我假设有一些我不明白的基础知识。

I assumed that frames contain their own 'grid space' (row, column) but the behavior I see doesn't bear that out, and I'm at a loss for getting things working the way I want for the top frame. My labels are supposed to be on the same row L to R, under a 'frame label' that spans the entire frame - except they don't. I want the actual to look more like the goal jpg, and I want to use grid to do it.

我假设框架包含它们自己的“网格空间”(行、列),但我看到的行为并不支持这一点,而且我对让顶部框架按照我想要的方式工作感到茫然。我的标签应该在 L 到 R 的同一行上,在跨越整个框架的“框架标签”下——除非它们没有。我希望实际看起来更像目标 jpg,我想使用网格来做到这一点。

You can just see one of the entry fields to the right of the green frame. Why is it going there ?

您只能看到绿框右侧的输入字段之一。为什么要去那里?

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

So specifically, where did my labels and Entry widgets go, and how do I get them to look more like the goal (top frame, the rest are for later).

具体来说,我的标签和 Entry 小部件去了哪里,以及如何让它们看起来更像目标(顶部框架,其余部分用于稍后)。

采纳答案by Bryan Oakley

I assumed that frames contain their own 'grid space'

我假设框架包含自己的“网格空间”

That is a correct assumption.

这是一个正确的假设。

You can just see one of the entry fields to the right of the green frame. Why is it going there ?

您只能看到绿框右侧的输入字段之一。为什么要去那里?

The problem starts here:

问题从这里开始:

top_frame = Frame(root, ...).grid(row=0, ...)

In python, x = y().z()will always set xto the result of .z(). In the case of top_frame = Frame(...).grid(...), grid(...)always returns Noneso top_framewill be None. That causes every widget that you think is going into the top frame to actually go in the root window.

在 python 中,x = y().z()将始终设置x.z(). 在的情况下top_frame = Frame(...).grid(...)grid(...)总是返回None所以top_frameNone。这会导致您认为进入顶部框架的每个小部件实际上进入根窗口。

Solution Overview

解决方案概述

As a general rule of thumb, you should never call grid, packor placeas part of the same statement that creates the widget. Partially it is for this exact behavior that you're experiencing, but also because I think it makes your code harder to write and harder to maintain over time.

作为一般经验法则,您永远不应该调用gridpack或者place作为创建小部件的同一语句的一部分。部分是因为您正在经历这种确切的行为,但也因为我认为随着时间的推移,它会使您的代码更难编写和维护。

Widget creation and widget layout are two different things. In my experience, layout problems are considerably easier to debug when you group your layout commands together.

小部件创建和小部件布局是两件不同的事情。根据我的经验,当您将布局命令组合在一起时,布局问题更容易调试。

Also, you should be consistent when using gridand always put the options in the same order so you can more easily visualize the layout. And finally, when using gridyou should get in the habit of always specifying the stickyoption, and always give one row and one column in each containing frame a non-zero weight.

此外,您在使用时应该保持一致,grid并始终以相同的顺序放置选项,以便您可以更轻松地可视化布局。最后,在使用grid时应该养成始终指定sticky选项的习惯,并始终为每个包含框架中的一行和一列赋予非零权重。

Solution Example

解决方案示例

Here's how I would write your code. It's much longer, but much easier to understand.

以下是我将如何编写您的代码。它更长,但更容易理解。

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

Result:

结果:

screenshot of running example

运行示例截图

回答by furas

variable = Widget(...).grid()assigns Noneto variable because grid()/pack()/place()return None

variable = Widget(...).grid()受让人None到的变量,因为grid()/ pack()/place()返回None

use

variable = Widget(...)
variable.grid() # .pack() .place()