2

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()
user1441004
  • 386
  • 1
  • 5
  • 13
  • 2
    That first link doesn't link to a question, it links to a search result. It's unclear which question you're talking about. You can get a link to the actual question from the `share` link below the list of tags. – Bryan Oakley Oct 08 '20 at 00:41
  • 2
    Why do you want to force the frame to a specific size? That's fairly unusual. Also, is there a reason you're only using `grid`? For the layout you're trying to achieve, it seems that `pack` might be the better solution. – Bryan Oakley Oct 08 '20 at 00:43
  • 3
    Note that `grid_rowconfigure()` and `grid_columnconfigure()` should be applied on the parent container to control the layout of its chidren. So you should call `root.grid_rowconfigure()` and `root.grid_columnconfigure()` to control `frame0`. Similarly you should call `frame0.grid_columnconfigure()` to control `frame1`. – acw1668 Oct 08 '20 at 04:03
  • Bryan, thank you for your responses. I updated the link to point to the proper answer - my bad, thanks for pointing that out. As for why I want to do what I am trying to do, I am a Tkinter noob and trying to learn. I'm following examples in "Modern Tkinter Examples for Busy Python Developers" by Mark Roseman, found at: https://tkdocs.com/ He suggests to do everything with Grid. – user1441004 Oct 08 '20 at 16:51
  • @acw1668 Thanks for your reply. You've got the problem half-solved. I was trying to configure `frame0` and `frame1` but had no call to configure `root`. That causes the Entry widget to now expand as I resize the main window which is just what I wanted. I will update the question to make clear the other part. – user1441004 Oct 08 '20 at 16:54
  • 1
    Then you need to use `root.grid_columnconfigure(0, weight=1, minsize=500)` and `root.grid_rowconfigure(0, weight=1, minsize=350)`. – acw1668 Oct 08 '20 at 17:07

1 Answers1

0

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()
user1441004
  • 386
  • 1
  • 5
  • 13
  • Another option is to call `frame0.grid_propagate(0)`, remove the two `minsize` options and add back `width=500, height=350` when creating `frame0`. – acw1668 Oct 08 '20 at 17:36