dogernout
dogernout

Reputation: 15

I can't place frames the way i want in tkinter

Good afternoon! Right to the heart of the matter: I have a window, it has a tab, and in it I want to place three main frames. One on the left, one on the right and one on the bottom. It is impossible to arrange the first two at the same level horizontally. Screenshots of how it looks now, and how I would like to see it, are attached. Here is a part of the code:

my_notebook.tab(current_tab, text=gang.name)
frame_left = Frame(current_tab, borderwidth=2, relief=GROOVE)  # THIS IS TOP LEFT FRAME
frame_left.pack(anchor=NW)
frame_right = Frame(current_tab, borderwidth=2, relief=GROOVE)  # THIS IS TOP RIGHT FRAME
frame_right.pack(anchor=NE)
f11 = LabelFrame(current_tab, borderwidth=2, pady=5, text="Founders", font=('arial', 14), relief=GROOVE) #  THIS IS BOTTOM FRAME
f11.pack(anchor=S, fill=BOTH)

NOW IN DREAMS

Upvotes: 0

Views: 103

Answers (2)

user7711283
user7711283

Reputation:

The solution is simple:

Use the tkinter .grid (manager) instead of using .pack

and arrange your frames in the 2x2 grid putting the third into the grid spanning two rows.

Just check out the tkinter documentation for how to use the grid manager for appropriate commands.

The advantage of using the grid manager in tkinter is that you have full control over placing your frames. You can even define empty columns and rows of chosen size in order to achieve visible spacing between the placed elements.

Using .pack is convenient, but can lead because of its automated and from user hidden logic to confusion. If it won't lead to confusion your question won't be here. Even if the most experienced tkinter poster here on stackoverflow recommends in his answer re-arranging the order of the pack commands, I would suggest to use the grid manager for more complex layouts and the pack manager only for the very simple ones.

Below the code demonstrating placing widgets into the grid:

import tkinter
root = tkinter.Tk()
L_l = tkinter.Label(root, text="LEFT")
L_r = tkinter.Label(root, text="RIGHT")
L_b = tkinter.Label(root, text="BOTTOM")
L_l.grid(row=1, column=1)
L_r.grid(row=1, column=2)
L_b.grid(row=2, column=1, columnspan=2)
# all the possible .grid() parameter: 
#   column, columnspan, in, ipadx, ipady, padx, pady, row, rowspan, sticky
root.mainloop()

creating:

enter image description here

Changing the padx, pady parameter of the .grid() to:

L_l.grid(row=1, column=1,  padx=50, pady=20)
L_r.grid(row=1, column=2,  padx=50, pady=20)
L_b.grid(row=2, column=1, columnspan=2, pady=30)

gives:

enter image description here

adding the code for appropriate values impacting the size of rows/columns respectively to others:

root.grid_rowconfigure(   1, weight=1)
root.grid_columnconfigure(1, weight=1)
root.grid_columnconfigure(2, weight=1)
# other possible parameter here is minsize= expressed in pixels
# to prevent too small sizes when shrinking tkinter window

will result in better response of the layout to resizing the tkinter window as shown in the picture below:

enter image description here

If you want that columns have same width even if sizes of the widgets in these columns are not the same use:

root.grid_columnconfigure(1, weight=1, uniform="groupID")
root.grid_columnconfigure(2, weight=1, uniform="groupID")
# groupID identifies columns which should be same width

(Same is valid concerning rows)

Upvotes: 0

Bryan Oakley
Bryan Oakley

Reputation: 385890

The order that you call pack matters, because the packer will place widgets on the side of remaining space. Once you put something on the left or right, it takes up the entire side, top to bottom.

The other problem is that you're not specifying the side, so the side defaults to "top". You need to use a side of "left" or "right" for the two at the top, and "bottom" for the one on the bottom.

The solution is to first pack the frame that is on the bottom, so that it takes up the entire bottom. When you pack widgets to the left or right they will take up the left or the right above the frame that is on the bottom.

Personally I find that grouping your calls to pack together makes solving layout problems much easier than interspersing them with the code that creates the widgets, like in the following example.

f11.pack(side="bottom", fill=BOTH)
frame_left.pack(side="left", fill=BOTH)
frame_right.pack(side="right", fill=BOTH)

For the canonical description of how the packer works, see The packer algorithm in the official tcl/tk manual pages.

Upvotes: 1

Related Questions