Why is TKinter OptionMenu changing the size of it's parent? Why is TKinter OptionMenu changing the size of it's parent? tkinter tkinter

Why is TKinter OptionMenu changing the size of it's parent?


The root of the problem lies in the fact you don't give any widgets a size, and all the frames are empty. The following description may sound confusing, but it's actually pretty logical, deterministic, and consistent with the documented behavior.

The natural size of the widgets and columns

Because none of the frames have an explicit width, they default to a width of 0 (zero). The optionmenu has the behavior that it adapts its size to be large enough to show the value (except on the Mac, I think). It is the only widget with a non-zero requested (or "natural") size.

The grid is responsible for the left and right sides. The left size is of zero width, and the right side is the width of the option menu. For the sake of this discussion let's say that it is 140 pixels wide just to make math easy; the actual size may be bigger or smaller depending on your fonts, and we're ignoring borders to keep the math simple. Therefore, grid thinks the left wants to be zero, and the right wants to be 140. That is the only information it starts with when it tries to make everything fit.

Dealing with extra space

You force the window to be 640 pixels wide but its children are only require 140 pixels, thus it has 500 extra pixels. You use column weights of three for the left and two for the right, so for every five pixels of extra space, three will go to the left and two will go to the right. That means that the left column gets 300 pixels of the extra space and the right column will get 200 pixels of the extra space. That makes the left column 300 pixels (0+300) and the right 340 (140+200). That's why they appear roughly the same size at startup.

What happens when you change the size of the optionmenu

Now, you change the value of the optionmenu, causing it to grow. Let's say the new width of the optionmenu is 440 pixels. The left side still wants to be zero, but now the right side wants to be 440. That means there are only 200 pixels of extra space: 120 for the left and 80 for the right. Remember, the left column's natural size is zero, so zero plus 120 means the left column will be 120 pixels wide. On the right, the natural size is 440. 440 plus the extra 80 means the right side will now be 520 pixels wide.

That is why, when there's a long option menu, the left side shrinks and the right side has extra space. You requested the left be zero, so it only gets to use the extra space after all of the other widgets with an actual size are laid out. The right side has a non-zero natural size, but the grid algorithm has space left over that it has to allocate to the right.

How to get uniform column widths

You didn't ask, but I'm going to assume a follow-up question will be "how do I make the two columns the same size?" The answer is to use the uniform option with grid. Tell grid you want the two columns to be of a uniform size like this:

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

uniform takes any string as an argument. All columns (or rows) with the same value are considered a "uniform group".

Note that with uniform, grid still honors the weight. it's just that with uniform the columns are guaranteed to strictly follow the column weights. In your case that means you have a 3:2 ratio between the left and right wide

Canonical information on grid and pack algorithms

Tkinter is a wrapper around a tcl interpreter with the tk toolkit. While the syntax is different than python, it's easy to translate the tcl documentation into python. Here are links to the descriptions of how grid and pack work: