1

I am teaching myself Python and attempting to build a local app that uses a window GUI. I am having a lot of trouble trying to layout the screen with grid(). I have searched and tried lots of different snippets of code, but I have the same problem, the frames and widgets don't seem to be formatting. The code below is really simplistic, but my end goal is to master how to use grid() so I can build any GUI I like in the future.

I want to be able to do the following:

--Window-----------------
| Section 1 | Section 2 |
|           |           |
-------------------------
| Section 3             |
|                       |
|                       |
-------------------------

from Tkinter import Button, Frame, Entry, Tk, Label, Menubutton, Menu, IntVar

class MainScreen(Frame):
def __init__(self, master):
    Frame.__init__(self, master)
    self.grid()
    self.searchSection()
    self.quitButton()


def searchSection(self):
    # Create Search Section
    self.searchFrame = Frame(self.master, bg='grey', relief='sunken', width=200, height=200)
    self.searchFrame.grid(row=0, column=0, rowspan=5, columnspan=30, sticky="wens")
    Label(self.searchFrame, text="Search :", bg='grey').grid(row=1, column=1, columnspan=20, sticky='w')
    self.searchField = Entry(self.searchFrame)
    self.searchField.grid(row=2, column=1, columnspan=7, sticky='w')
    #Create Menu Options
    self.search = Menubutton(self.searchFrame, text = "Search", bg='grey')
    self.search.grid(row=2, column=8, columnspan=3, sticky='w')
    self.search.menu = Menu(self.search, tearoff = 0)
    self.search['menu'] = self.search.menu       
    self.SearchType1Var = IntVar()
    self.search.menu.add_checkbutton(label="SearchType1", variable = self.SearchType1Var)


def quitButton(self):
    ## Provide a quit button to exit the rogram
    self.quitFrame = Frame(self.master, bg='grey', width=50, height=50)
    self.quitFrame.grid(row=0, column=20, rowspan=5, columnspan=5, sticky='ewns')
    self.quitButton = Button(self.quitFrame, text="Quit", command=exit)
    self.quitButton.grid()


if __name__ == '__main__':

root = Tk()
root.title("Learn Grid GUI")
root.geometry("800x600+200+150")
main = MainScreen(root)
root.mainloop()
user2314737
  • 27,088
  • 20
  • 102
  • 114
TXTank
  • 25
  • 1
  • 6
  • What is your question? The `grid()` option parameters are misused in general, but you don't formulate any concrete question. – A. Rodas Mar 22 '13 at 15:32
  • Apologies - my GUI comes out jumbled up, and I can't figure out how to sort it. – TXTank Mar 22 '13 at 15:45
  • Just taking a stab here, as I'm learning myself... but it seems like you've got Frames within Frames, which may be making the grid not work as anticipated. – memilanuk Mar 22 '13 at 16:39
  • @memilanuk - I thought that was possible to 'split' the screen. See this post- http://stackoverflow.com/questions/6129899/python-multiple-frames-with-grid-manager – TXTank Mar 22 '13 at 20:20
  • It is... but I think you are inter-mixing the grid layout from the master/parent Frame with the grid layouts of the widgets, which you have inside the child Frames. I believe the grid layout inside each frame is independent of the others. Also, take a look at the solution in that thread - rowconfigure and columnconfigure. I'm personally not experienced with them, but I'm guessing that may be why some of your rows & columns aren't showing as expected. – memilanuk Mar 22 '13 at 20:50
  • Your question is hard to understand. The ascii drawing you added shows a window with three sections: section 1, section 2 and section 3. However, your example code makes no mention of a frame named "window", nor one named "Section 1", "Section 2" or "Section 3". For example, is "searchFrame" supposed to be one of the sections, or is it the window? – Bryan Oakley Mar 25 '13 at 15:41

2 Answers2

2

Your instincts of using subframes is good, but your implementation is making the problem harder than it should be. For a general rule of thumb, I advise against having different functions creating widgets and placing them in their parent. Put another way, all of the grid or pack statements for a given container should normally all be in the same function.

In my experience, the best way to accomplish a layout is to "divide and conquer". For example, your ascii drawing shows three sections. Start with that, and only that. Create three frames, one for each section. Get them placed appropriately in their container before trying to add anything to them.

When I do this, I first give each frame a distinct color and an explicit size just for visualization purposes. For example:

import Tkinter as tk

class Example(tk.Frame):
    def __init__(self, master, *args, **kwargs):
        tk.Frame.__init__(self, master, *args, **kwargs)
        self.master = master
        self.s1 = tk.Frame(self, background="pink", width=200, height=200)
        self.s2 = tk.Frame(self, background="blue", width=200, height=200)
        self.s3 = tk.Frame(self, background="bisque", width=200, height=200)

        self.s1.grid(row=0, column=0, sticky="nsew")
        self.s2.grid(row=0, column=1, sticky="nsew")
        self.s3.grid(row=1, column=0, columnspan=2, sticky="nsew")

        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(1, weight=1)

if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(side="top", fill="both", expand=True)
    root.mainloop()

Once I have that working and resizing properly, I can then move on to adding widgets, one section at a time. Since I've already got the main parts of the GUI responding appropriately to window resizes, I can focus all my efforts on a single section without worrying about how they affect the rest of the program.

It's important to know that when you add widgets to one of these sections, the rows and columns within that section are independent of any other widgets. For example, if you put something in column one of section 2, that refers to column one inside section two, not the absolute column of the GUI as a whole.

For illustrative purposes, let's assume you want the search label, entry widget, and the menu button all to go in section 3 (I can't tell from your question where you want them to go). In this case, the label goes on row 0 and spans two columns, and the entry widget and menubutton go below, in separate columns. I assume you want the first column to grow and shrink.

This requires two modifications to the program. The first is to create the searchSection function, which creates the widgets in the search section. The second modification is to call this function in the constructor of the GUI.

Here's a fully working final version:

import Tkinter as tk

class Example(tk.Frame):
    def __init__(self, master, *args, **kwargs):
        tk.Frame.__init__(self, master, *args, **kwargs)

        self.s1 = tk.Frame(self, background="pink", width=200, height=200)
        self.s2 = tk.Frame(self, background="blue", width=200, height=200)
        self.s3 = tk.Frame(self, background="bisque", width=200, height=200)

        self.s1.grid(row=0, column=0, sticky="nsew")
        self.s2.grid(row=0, column=1, sticky="nsew")
        self.s3.grid(row=1, column=0, columnspan=2, sticky="nsew")

        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(1, weight=1)

        # now create the search section
        self.searchSection(self.s1)

    def searchSection(self, parent):
        l = tk.Label(parent, text="Search :", bg='grey')
        self.searchField = tk.Entry(parent)
        self.search = tk.Menubutton(parent, text="Search", bg="grey")
        self.search.menu = tk.Menu(self.search, tearoff = 0)
        self.search['menu'] = self.search.menu
        self.SearchType1Var = tk.IntVar()
        self.search.menu.add_checkbutton(label="SearchType1", 
                                         variable = self.SearchType1Var)

        l.grid(row=0, column=0, columnspan=2, sticky='w')
        self.searchField.grid(row=1, column=0, sticky="ew")
        self.search.grid(row=1, column=1, sticky="ew")

        parent.grid_columnconfigure(0, weight=1)

if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(side="top", fill="both", expand=True)
    root.mainloop()
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Yes! Thanks! I understand now. I assumed I could build subframes within the parent frame, and then build the sub grids. I understand now that I have to use the parent grid to configure the sub frames. – TXTank Mar 27 '13 at 12:49
  • I copied what you wrote and started to modify it, but I noticed that once I start placing widgets in the sub-frames, the sub-frame resizes to the widgets, instead of the specified size in the Frame() command. Is this possibly due to the row/column_configure commands? – TXTank Mar 27 '13 at 13:56
  • @TXTank: no, that is simply how Tkinter is designed to work. Rarely do you actually want a containing frame to be a static size. The example used a fixed size simply so that you could see the frames when they contained nothing. Normally you want frames to grow and shrink along with its contents. You can turn this feature off, but it almost never is the right thing to do. If you want to learn how, search this site for "[tkinter] geometry propagation". – Bryan Oakley Mar 27 '13 at 14:09
  • Okay - this is where I need to learn best practice... So my intent is a small window appears with the search feature. When the search is performed, and data is returned, I was going to have the data (15 - 20 parts) appear down below (Frame 3). Without the fields in frame 3, the window is very small and I get a feeling detriment to the UI. What is the best practice for something like this? – TXTank Mar 27 '13 at 14:47
0

If I understood correctly, your problem is that you cant sort the GUI. The answer is pretty simple - if you want to sort the GUI just put the code in the same order that you want the window to show. For example:

 --Window--
| text box |
|  button  |
|          |
------------

-Code-
[text box code here]
[button code here]
root.mainloop()

Ive been working with tkinter for a long time and it worked for me. Good luck and happy holydays!

LStyle

LStyle
  • 1
  • 3
  • not exactly what I am looking for - See my ASCII layout at the top of the original post code. – TXTank Mar 25 '13 at 14:24