In short, the packer isn't designed to directly create the layout you're trying to create. You can do it, but it requires some extra frames. In this particular case where you're clearly trying to create a grid, grid
is arguably the better choice.
Before I get to an explanation for why this is so, let me suggest a solution. Create another frame called "CD" which will be used to hold both C
and D
. You can then pack C
to the left and D
to the right, and then place this frame below B
. That is how you achieve the desired result using the packer.
A = tk.LabelFrame(root,text='A', bd=2)
B = tk.LabelFrame(root,text='B', bd=2)
CD = tk.Frame(root)
C = tk.LabelFrame(CD,text='C', bd=2)
D = tk.LabelFrame(CD,text='D', bd=2)
E = tk.LabelFrame(root,text='E', bd=2)
C.pack(side=tk.LEFT,fill=tk.BOTH, expand=tk.TRUE)
D.pack(side=tk.RIGHT,fill=tk.BOTH, expand=tk.TRUE)
A.pack(fill=tk.BOTH, expand=tk.TRUE)
B.pack(fill=tk.BOTH, expand=tk.TRUE)
CD.pack(fill=tk.BOTH, expand=tk.TRUE)
E.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=tk.TRUE)
Explaining the packer
The packer works by reserving a parcel of space along the side of unallocated space. This allocated space takes up the full width of the unallocated space when packing the widget to the top or bottom, and takes up the full height when packing on the left or right. This is an important detail.
Let me try to describe it with some screenshots. In all cases, the following screenshots do not show the frames, they show the amount of allocated and unallocated space being managed by the packer.
When you pack A
along the top (top is the default if you don't specify a side), a parcel of space is reserved for the full width of the root window. And because you packed it to the top, the only remaining space is below A
. Nothing can be packed to the left or right of A
from this point on.
(Actually, you can put things to the left or right by using some advanced options, but that's beyond the scope of this description)
When you pack B along the top, the only available space is below A
. Again, because you packed it along the top, after packing B
the only available free space now will be below B
.
When you pack C
along the left, a parcel of space is reserved for the full height of the remaining space. That means nothing will be able to be placed below C
. All of the remaining space is to the right of C
, and below B
.
- When you pack
D
, it must go to the right of C
and below B
. Because you pack it to the right, it will reserve all remaining vertical space above and below D
.
When you pack E
along the bottom, the only place it can go is below B
, to the right of C
, and to the left of D
.
Because of the nature of the packer allocating all space along a side, the packer works best when all widgets are placed on the same axis - either stacked vertically or horizontally. When you want to switch the axis as you did with C
and D
, its usually best to put them in side a separate frame. Within that frame you can put widgets left-to-right, but the frame can remain in the top-to-bottom axis as the other widgets.
Note: this is what is actually happening in your code: E
is being squeezed between C
and D
. It's not visible for various reasons, but if you were to give it an explicit size and color then it would show up.
For more information
The authoritative description of the packer algorithm can be found in the tcl/tk man pages for pack.