Search code examples
pythonpython-2.7tkinterwizard

How to make a simple wizard using grid() in Tkinter?


Forgive me. I am new to Tkinter and only have a simple/modest understanding of python. My overall goal is to make a wizard-like program where the user inputs ever-increasing specifics as the program goes on (with certain frames appearing depending on certain inputs). I am trying just to get the core wizard idea working and am running into some problems. Here is my code (I have commented out things that other sources imply are on the right track but have failed for me):

from Tkinter import *
root = Tk()
#root.minsize(300,300) ?
#root.geometry("300x300") ?

def next():
    move(+1)

def prev():
    move(-1)

def exit_program():
    root.destroy()

page1 = Frame(root, width=300, height=300)
page1.grid()
#page1.grid(row=0,column=0, sticky="nsew") ?
#page1.grid_rowconfigure(0, weight=1) ?
#page1.grid_columnconfigure(0, weight=1) ?
p1_label = Label(page1, text='This is page 1 of the wizard.').grid(column=1, row=0)
p1_quit = Button(page1, text="Quit", command=exit_program).grid(column=1, row=2)
p1_next = Button(page1, text="Next", command=next).grid(column=2, row=2)

page2 = Frame(root)
p2_label = Label(page2, text='This is page 2 of the wizard.').grid(column=1, row=0)
p2_prev = Button(page2, text="Prev", command=prev).grid(column=1, row=2)
p2_next = Button(page2, text="Next", command=next).grid(column=2, row=2)

page3 = Frame(root)
p3_label = Label(page3, text='This is page 3 of the wizard.').grid(column=1, row=0)
p3_prev = Button(page3, text="Prev", command=prev).grid(column=1, row=2)
p3_quit = Button(page3, text="Quit", command=exit_program).grid(column=2, row=2)

pages = [page1, page2, page3]
current = page1
def move(dirn):
    global current
    idx = pages.index(current) + dirn
    if not 0 <= idx < len(pages):
        return
   current.grid_forget()
   current = pages[idx]
   current.grid()

root.mainloop()

I have a few questions:

  • Why does the first (and all) frame(s) shrink to the size of widgets inside, even though I have set the width and height to be a certain amount? I have looked online and apparently grid_propagate(False) turns off the re-sizing but it is both highly NOT recommended and straight-up unsuccessful (yes it makes the window the dimensions I want, but the "grid" itself is still in the upper-left). Shouldn't I be able to state the dimensions of a frame, and the grid aligns itself with those dimensions (i.e. grid organization is preserved, just not the area)? Is this problem linked to the wizard-process? I would prefer not too but I can probably still write the program in one window.
  • Why does the grid appear to be 2x2? Shouldn't it be 3x3 because the zeroth entry is valid? I have placed a button (p1_next) in position (2x2). Is it because nothing is in the 0 column, grid() removes it and shifts everything to the left?
  • Is this the best approach for what I'm trying to accomplish? I'm afraid I only know the absolute basics of OOP and would prefer to avoid if possible (also this program, while big for me, is going to end up being minuscule by modern software development standards).

In my experience of learning things, I have an inkling that the issue is not a quick fix, and that I need a big ol paradigm shift to understand this. Either way, any help would be much appreciated

I'm sorry if this is a duplicate. And thanks!


Solution

  • Why does the first (and all) frame(s) shrink to the size of widgets inside, even though I have set the width and height to be a certain amount? ... Shouldn't I be able to state the dimensions of a frame, and the grid aligns itself with those dimensions

    This is simply how tkinter is designed to work: containers shrink to fit their contents. 99% of the time this is the right solution. As you observed, you can turn geometry propagation off, but that has side effects, and requires you to do work that is usually better handled by tkinter. If you really insist on the frame being a specific size, turning off propagation is typically how you do it.

    If your specific case, it makes more sense to force the main window to be a specific size rather than force the frames to be a specific size. The frames will then grow (or shrink) to fit the main window. You can do this using the geometry method of the root window.

    Why does the grid appear to be 2x2? Shouldn't it be 3x3 because the zeroth entry is valid? I have placed a button (p1_next) in position (2x2). Is it because nothing is in the 0 column, grid() removes it and shifts everything to the left?

    If nothing is in a column, that column will have a default width of zero (unless it's part of a uniform group, or has a minsize, etc). The same is true for rows -- empty rows by default have a height of zero.

    Is this the best approach for what I'm trying to accomplish?

    That's hard to answer. There probably isn't a "best" way.

    You might want to look at this answer to a related question, which shows a way to toggle between a set of frames by stacking them and then raising the current one to the top of the stack.