Python Tkinter Frame layout, weight, and resizing, Grid geometry manager

988 Views Asked by At

I guess I am not understanding something about the way Grid works...

My question seems related to this SO question: Python tkinter Text widget fill fixed sized frame using grid

To which the answer was that weight needed to be given to an item in order have it take up the extra space, using the functions grid_columnconfigure() and grid_rowconfigure().

Below is the code for a simple example. What I am trying to achieve is to be able to specify the size of frame0, have it be stuck to all sides of the root window, and then have the child frame, frame1 be stuck to frame0 on left, top, right, and to stretch/shrink when the main window of the app is resized.

So, initially, I would expect the application to launch at basically 500x350 size. frame1 would be as high as it naturally is and basically 500 pixels wide (minus a little for padding).

After acw1668's comment, I updated the code to configure root and set it's weight to 1. The size of Entry now varies to take up any horizontal space, just as I wanted. But the GUI still launches at "natural" size, though I have given an explicit size to frame0. I'm not understanding why the geometry manager does not treat 500x350 as the natural size and allocate that?

Can anybody see how to get the initial launch sized as expected?

#!/usr/bin/env python3

from tkinter import *
from tkinter import ttk

root = Tk()
root.title("Layout Problem")
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)

frame0 = ttk.Frame(root, padding=4, width=500, height=350)
frame0.grid_columnconfigure(0, weight=1)
frame0.grid_rowconfigure(0, weight=1)
frame0.grid(column=0, row=0, sticky=(W, N, E, S))

frame1 = ttk.Frame(frame0, padding=4)
frame1.grid_columnconfigure(1, weight=1)
frame1['borderwidth'] = 2
frame1['relief'] = "ridge"
frame1.grid(column=0, row=0, sticky=(W, N, E))

# add widgets to 'frame1'
ttk.Label(frame1, text="Label: ").grid(row=0, column=0, sticky=W)

entryValue = StringVar()
ttk.Entry(frame1, textvariable=entryValue)\
    .grid(row=0, column=1, sticky=(W, E))
entryValue.set("Entry")

ttk.Button(frame1, text="Button")\
    .grid(row=0, column=2, sticky=E)

root.mainloop()
1

There are 1 best solutions below

1
On

For reference, below is the code after incorporating acw1668's suggestions.

The GUI now launches at expected size. There is sort of a secondary issue in that now the frame doesn't shrink below 500 px width (i.e., the Entry will not collapse back to natural size) though you can force the application window to be smaller. That's sort of a separate issue.

I can see there is some subtlety to this whole layout and resizing business and I've yet got a ways to go. ;)

Hopefully this question will have some pedagogic value to others following the same trail:

#!/usr/bin/env python3

from tkinter import *
from tkinter import ttk

root = Tk()
root.title("Layout Problem")
root.grid_columnconfigure(0, weight=1, minsize=500)
root.grid_rowconfigure(0, weight=1, minsize=350)

frame0 = ttk.Frame(root, padding=4)
frame0.grid(column=0, row=0, sticky=(W, N, E, S))
frame0.grid_columnconfigure(0, weight=1)
frame0.grid_rowconfigure(0, weight=1)

frame1 = ttk.Frame(frame0, padding=4)
frame1.grid_columnconfigure(1, weight=1)
frame1['borderwidth'] = 2
frame1['relief'] = "ridge"
frame1.grid(column=0, row=0, sticky=(W, N, E))

# add widgets to 'frame1'
ttk.Label(frame1, text="Label: ").grid(row=0, column=0, sticky=W)

entryValue = StringVar()
ttk.Entry(frame1, textvariable=entryValue)\
    .grid(row=0, column=1, sticky=(W, E))
entryValue.set("Entry")

ttk.Button(frame1, text="Button")\
    .grid(row=0, column=2, sticky=E)

root.mainloop()