tkinter grid: distribute rows and columns over frame height and width
Question: Using python 3.4.1 on Mac OS I'm trying to distribute label and entry widgets
equally using the grid geometry manager in a subframe called 'lowerframe'.

My current MWE is shown below:

    
    
    #!/usr/bin/env python3
    
    from tkinter import *
    from tkinter import ttk
    
    class Window(Frame):
        def __init__(self, master=None):
            Frame.__init__(self, master)
            # create master window
            self.master = master
    
            # create root window on initialization
            self.create_rootwindow()
    
        def create_rootwindow(self):
            self.master.title("GUI")
            self.master.geometry("1024x748")
            self.master.resizable(width=FALSE, height=FALSE)
    
            self.create_upperframe()
            self.create_lowerframe()
            self.create_inputentries()
            self.create_btnframe()
            self.create_inputbtn()
    
        def create_upperframe(self):
            self.upperframe = Frame(self.master, width=980, height=490)
            self.upperframe.config(background="#339900")
            self.upperframe.place(x=20, y=10)
    
        def create_lowerframe(self):
            self.lowerframe = Frame(self.master, width=830, height=200)
            self.lowerframe.config(background="#336699")
            self.lowerframe.place(x=20, y=530)
    
        def create_inputentries(self):
            self.create_lowerframe()
    
            parameternames = [
                ('a', 'U'), ('b', 'U'), ('c', 'U'), ('d', 'U'), ('e', 'U'),
                ('f', 'U'), ('g', 'U'), ('h', 'U'), ('i', 'U'), ('j', 'U'),
                ('k', 'U'), ('l', 'U'), ('m', 'U'), ('n', 'U'), ('o', 'U'),
                ('p', 'U'), ('q', 'U'), ('r', 'U'), ('s', 'U'), ('t', 'U')]
    
            for i, data in enumerate(parameternames):
                r = i % 5
                c = (i // 5) * 3
                Label(self.lowerframe, text=data[0]).grid(row=r, column=c, pady=4, padx=0)
                Entry(self.lowerframe, width=10).grid(row=r, column=c+1, pady=4, padx=0)
                Label(self.lowerframe, text=data[1]).grid(row=r, column=c+2, pady=4, padx=0)
    
        def create_btnframe(self):
            self.btnframe = Frame(self.master, width=130, height=200)
            self.btnframe.place(x=870, y=530)
    
        def create_inputbtn(self):
            self.create_btnframe()
    
            startanalysis_btn = Button(self.btnframe, text="Start Analysis", width=12, command=self.do_nothing)
            startanalysis_btn.place(x=0, y=0)
    
            abortanalysis_btn = Button(self.btnframe, text="Abort Analysis", width=12, command=self.do_nothing)
            abortanalysis_btn.place(x=0, y=50)
    
            resetanalysis_btn = Button(self.btnframe, text="Reset Analysis", width=12, command=self.do_nothing)
            resetanalysis_btn.place(x=0, y=100)
    
            showresults_btn = Button(self.btnframe, text="Show Results", width=12, command=self.do_nothing)
            showresults_btn.place(x=0, y=200, anchor=SW)
    
        def do_nothing(self):
            pass
    
    root = Tk()
    
    app = Window(root)
    
    root.mainloop()
    

As you can see, each "set" of widgets in the lower, blue frame (called
'lowerframe') consists of a label with the description (here 'a' to 't'), a
entry widget and another label widget with the according unit of the input
value (here 'U' for all labels).

Using these "sets" I need to create five rows and 4 "set columns" (12 columns
using grid geometry manager currently). My aim is to distribute those rows and
"set columns" over to the specified height and width of lowerframe.

\-- EDIT: I uploaded a
[sketch](https://dl.dropboxusercontent.com/u/7203428/SO/lowerframe_sketch.png)
to my Dropbox folder showing how the result should look like.


Answer: The way you've written your code makes it very hard to modify. For one, as a
rule of thumb you should never use `place`. There's simply no need because
`pack` and `grid` provide much more functionality.

Second, as another rule of thumb, a parent should be responsible for laying
out its children -- don't have a function that creates a frame also call
`grid`, `pack`, or `place` to put itself in its parent. If you decide to
change your layout you end up having to change a bunch of functions instead of
one.

Finally, when using grid you need to give rows and columns "weight" if you
want them to grow to fill their containing window.

Here's how I would rewrite your code:

    
    
    from tkinter import *
    
    class Window(Frame):
        def __init__(self, master=None):
            Frame.__init__(self, master)
            # create master window
            self.master = master
    
            # create root window on initialization
            self.create_rootwindow()
    
        def create_rootwindow(self):
            self.master.title("GUI")
            self.master.geometry("1024x748")
    
            self.create_upperframe()
            self.create_lowerframe()
            self.create_inputentries()
            self.create_btnframe()
            self.create_inputbtn()
    
            self.upperframe.pack(side="top", fill="both", expand=True, padx=4)
            self.lowerframe.pack(side="left", fill="both", expand=True, padx=4, pady=4)
            self.btnframe.pack(side="right", fill="both", padx=4, pady=4)
    
        def create_upperframe(self):
            self.upperframe = Frame(self.master, width=980, height=490)
            self.upperframe.config(background="#339900")
    
        def create_lowerframe(self):
            self.lowerframe = Frame(self.master, width=830, height=200)
            self.lowerframe.config(background="#336699")
    
        def create_inputentries(self):
            self.create_lowerframe()
    
            parameternames = [
                ('a', 'U'), ('b', 'U'), ('c', 'U'), ('d', 'U'), ('e', 'U'),
                ('f', 'U'), ('g', 'U'), ('h', 'U'), ('i', 'U'), ('j', 'U'),
                ('k', 'U'), ('l', 'U'), ('m', 'U'), ('n', 'U'), ('o', 'U'),
                ('p', 'U'), ('q', 'U'), ('r', 'U'), ('s', 'U'), ('t', 'U')]
    
            for i, data in enumerate(parameternames):
                r = i % 5
                c = (i // 5) * 3
                Label(self.lowerframe, text=data[0]).grid(row=r, column=c, pady=4, padx=0, sticky="nsew")
                Entry(self.lowerframe, width=10).grid(row=r, column=c+1, pady=4, padx=0, sticky="ew")
                Label(self.lowerframe, text=data[1]).grid(row=r, column=c+2, pady=4, padx=0, sticky="nswe")
    
                self.lowerframe.grid_columnconfigure(c+1, weight=1)
    
    
        def create_btnframe(self):
            self.btnframe = Frame(self.master, width=130, height=200)
    
        def create_inputbtn(self):
            self.create_btnframe()
    
            startanalysis_btn = Button(self.btnframe, text="Start Analysis", width=12, command=self.do_nothing)
            abortanalysis_btn = Button(self.btnframe, text="Abort Analysis", width=12, command=self.do_nothing)
            resetanalysis_btn = Button(self.btnframe, text="Reset Analysis", width=12, command=self.do_nothing)
            showresults_btn = Button(self.btnframe, text="Show Results", width=12, command=self.do_nothing)
    
            startanalysis_btn.pack(side="top", fill="x")
            abortanalysis_btn.pack(side="top", fill="x")
            resetanalysis_btn.pack(side="top", fill="x")
            showresults_btn.pack(side="top", fill="x")
    
        def do_nothing(self):
            pass
    
    root = Tk()
    app = Window(root)
    root.mainloop()
    

**Things to notice:**

  * I've replaced all uses of `place` with `pack` (though `grid` would work just as well)
  * I've grouped the `pack`ing of the major areas together after they have been created
  * I've grouped the `pack`ing of the buttons together, making it arguably easier to visualize and modify
  * I've added a weight to the columns that have entry widgets in the bottom frame. That causes those columns to grow or shrink to fill any extra space
  * I've removed setting resizable to false. In general I think the user should be allowed to choose the size of the GUI. Plus, it illustrates that by using `pack` and/or `grid` instead of `place`, you get proper resize behavior without any extra effort. If you really think you know better than your users, you can put it back in. 

The code now has good resize behavior, the grid of entry widgets expands to
fill its container, and the functions are less tightly coupled since a
function that creates a frame doesn't have to know how that frame will be
displayed.

