为什么TKinter OptionMenu会更改其父级的大小?

时间:2016-06-16 23:30:27

标签: python tkinter grid-layout optionmenu

我有这个GUI程序,其中一个框架中有一个OptionMenu。每当我在OptionMenu中选择某些内容时,它会调整父框架的大小,即使它有足够的空间放在当前面板中。用文字描述很难,所以这是我的意思的图像:

You can see that the purple, blue, and red frames have expanded with the size increase of the OptionMenu

您可以看到紫色,蓝色和红色框架随着OptionMenu的大小增加而扩展。

窗口分为两个框架,左侧和右侧,网格布局,重量分别为3和2。两个框架内部是每个彩色面板的包装布局,设置为填充X.在紫色内部,我已设置此选项菜单,并将其打包到面板的左侧。

当它改变其内容时,它会调整整个右框架的大小,忽略网格权重并抛弃GUI的平衡。如果我为OptionMenu设置固定宽度,它不会调整大小,但仍然会使帧与GridLayout不对齐。如何根据这一个元素的宽度调整帧的大小,只需将元素放在框架内部,框架内有足够的空间来处理它,即使它最宽也是如此?

这是我正在使用的GUI代码的简化版本,完整代码有点太长,因为每个面板都被分成了类以备将来的功能:

root = Tk()
root.geometry('640x480')

#Begin defining left frame areas
leftFrame = Frame(root)

grayPanel = Frame(leftFrame,bg="gray")
whitePanel = Frame(leftFrame,bg="white", height=50)
grayPanel.pack(expand=True,fill=BOTH)
whitePanel.pack(fill=X)

#Begin defining right frame areas
rightFrame = Frame(root)

purplePanel = Frame(rightFrame,bg="purple", height=50)
bluePanel = Frame(rightFrame,bg="blue")
redPanel = Frame(rightFrame,bg="red", height=100)

purplePanel.pack(fill=X)
bluePanel.pack(expand=True,fill=BOTH)
redPanel.pack(fill=X)

#create the options dropdown for purple
currentOption = StringVar(purplePanel)
currentOption.set("None")
optList = ["None","Some incredibly long string that breaks everything"]
options = OptionMenu(purplePanel,currentOption,*optList)
options.pack(side=LEFT)


leftFrame.grid(row=0,column=0,sticky=N+S+E+W)
rightFrame.grid(row=0,column=1,sticky=N+S+E+W)

root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=3)
root.grid_columnconfigure(1, weight=2)

root.mainloop()

1 个答案:

答案 0 :(得分:2)

问题的根源在于你不给任何小部件一个大小,所有的框架都是空的。以下描述可能听起来令人困惑,但它实际上非常符合逻辑,确定性并且与记录的行为一致。

小部件和列的自然大小

由于没有任何帧具有明确的宽度,因此默认宽度为0(零)。 optionmenu的行为是它调整其大小足以显示值(我认为除了在Mac上)。它是唯一具有非零请求(或“自然”)大小的小部件。

网格负责左侧和右侧。左侧大小为零宽度,右侧为选项菜单的宽度。为了便于讨论,我们可以说它只有140像素宽才能使数学变得简单;实际大小可能会更大或更小,具体取决于您的字体,我们忽略边框以保持数学简单。因此,网格认为左边想要为零,右边想要为140.这是它在尝试使一切适合时开始的唯一信息。

处理额外空间

您强制窗口宽度为640像素,但其子窗口只需要140像素,因此它有500个额外像素。左侧使用三列权重,右侧使用两列权重,因此对于额外空间的每五个像素,三个将向左移动,两个将向右移动。这意味着左列获得300个像素的额外空间,右列将获得200个像素的额外空间。这使得左列300像素(0 + 300)和右340(140 + 200)。这就是他们在启动时看起来大致相同的原因。

更改optionmenu

的大小时会发生什么

现在,您更改optionmenu的值,使其增长。假设optionmenu的新宽度为440像素。左侧仍然想要为零,但现在右侧想要为440.这意味着只有200像素的额外空间:左边是120,右边是80。请记住,左列的自然大小为零,因此零加120意味着左列的宽度为120像素。在右边,自然尺寸是440. 440加上额外的80意味着右边现在将是520像素宽。

这就是为什么当有一个长选项菜单时,左侧收缩,右侧有额外空间。您请求左边为零,因此只有在布局了所有其他具有实际大小的小部件后才能使用额外空间。右侧具有非零自然大小,但网格算法还有剩余空间,必须分配到右侧。

如何获得统一的列宽

你没有问,但我会假设一个后续问题是“如何让这两列的大小相同?”答案是在网格中使用uniform选项。告诉网格您希望两列具有如下统一大小:

root.grid_columnconfigure(0, weight=3, uniform="column")
root.grid_columnconfigure(1, weight=2, uniform="column")

uniform将任何字符串作为参数。具有相同值的所有列(或行)都被视为“统一组”。

请注意,对于uniform,网格仍然可以衡量权重。只有uniform才能确保列严格遵循列权重。在您的情况下,这意味着左右宽度之间的比率为3:2

关于网格和包算法的规范信息

Tkinter是使用tk工具包的tcl解释器的包装器。虽然语法与python不同,但很容易将tcl文档翻译成python。以下是gridpack工作方式说明的链接: