I would really appreciate some help with figuring out grid
geometry manager.
Here is what I want to build.
I was thinking of using grid but I cannot find any good tutorials that would clearly explain how to work with it. There are lots of tutorials but mostly all are either very simple or really outdated.
I am not sure how to build what is shown in the picture using only grid because all elements are nested inside each other and each element is supposed to hold more elements inside it. It's not so hard to arrange outermost widgets using grid. I just place Toolbar into 0th row, then outermost PanedWidow (green) into 1st row, and then Status Bar into 2nd row. After that I need to arrange things inside green PanedWindow. I place another PanedWindow (pink) into the right pane of the green PanedWindow and then stick a Notebook into it's top pane.
Now, I need to add more widgets to these inner panes. For instance. I am going to add some buttons to the bottom pane of the pink PanedWindow. And that's where I run into problems.
If I try to use pack()
to arrange things inside these innermost panes, Python screams at me for
using more than one geometry manager.
But when I think about how to accomplish this with grid
, I just can't find a way to subdivide
innermost panes into smaller grids.
Can there be grids inside Widgets which have been acted upon by an outer grid?
When I see widgets that take up the full width or full height of an area I usually use pack
since it's specifically designed to lay objects along a side of an empty cavity. You can use grid
but it requires extra code since you have to both add the widget and configure the rows and columns. With pack
all you have to do is add the widgets.
For example, it's clear you want a statusbar along the bottom, and a toolbar along the top, and a paned widget in-between. So, start with that, as in the following example:
import tkinter as tk
root = tk.Tk()
root.geometry("600x400")
toolbar = tk.Frame(root, background="#d5e8d4", height=40)
statusbar = tk.Frame(root, background="#e3e3e3", height=20)
main = tk.PanedWindow(root, background="#99fb99")
toolbar.pack(side="top", fill="x")
statusbar.pack(side="bottom", fill="x")
main.pack(side="top", fill="both", expand=True)
root.mainloop()
Note: widths, heights, and colors are added to the frame for illustrative purposes since otherwise an empty frame would have a size of 1x1 and be invisible. Once you add widgets inside a frame you can remove these options.
You say the right will have a paned window, so add that on the right. We'll use a normal frame on the left.
left_pane = tk.Frame(main, background="#99fb99", width=100)
right_pane = tk.PanedWindow(main, background="#99fb99", width=200)
main.add(left_pane)
main.add(right_pane)
Next, add the two panes to the right. So that I can show colors with as little code as possible I'll use a frame on the top instead of a notebook:
notebook = tk.Frame(right_pane, background="#99ceff", height=70)
bottom_right = tk.Frame(right_pane, background="#ffe6cd", height=50)
right_pane.add(notebook)
right_pane.add(bottom_right)
With all that being said, you can use grid
if you want. The trick is to use intermediate frames, since the layout in any widget is independent of the layout in parent or child widgets.
All you need to do is remove the first three calls to pack
and replace it with these five lines:
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
toolbar.grid(row=0, column=0, sticky="ew")
main.grid(row=1, column=0, sticky="nsew")
statusbar.grid(row=2, column=0, sticky="ew")
Since the other widgets are children of paned widgets, there's nothing else to do. Any widgets you add to each pane have their own independent layout area, so you can use grid
, pack
, or place
inside each frame.
To illustrate that point, I'll use grid
to add several rows and columns of squares:
for row in range(6):
for column in range(30):
f = tk.Frame(bottom_right, background="white",
bd=2, relief="raised", width=10, height=10)
f.grid(row=row, column=column)