5

I am designing GUIs for my python programs using Tkinter's 'grid()' method.

Is there a way to let the widgets scale with the master window?

Here's a short example:

from Tkinter import *

master = Tk()

Label(master, text="This is a test").grid(row=0, column=0)

mytext1 = Text(master, width=30, height=5)
mytext1.grid(row=1, column=0)

mytext2 = Text(master, width=30, height=5)
mytext2.grid(row=3, column=0)

master.mainloop()

What I'd like to do is have the widgets adjust their sizes when the size of the master window is changed. (For such small GUIs it's no problem, but when there are a lot of widgets this gets desirable.)

Any help would be greatly appreciated!

j_4321
  • 15,431
  • 3
  • 34
  • 61
CodingCat
  • 4,999
  • 10
  • 37
  • 59

2 Answers2

3

You would want to configure the rows/columns to have weight so they can expand when you resize the window. Also, you want the widgets to by sticky to the sides of their cells. Not only do the frame rows/columns need weight, but so do all of the rows and columns within frame, hence the for loops.

from Tkinter import *

class MyFrame(Frame):
    def __init__(self, master):
        Frame.__init__(self, master)
        self.grid(row=0, column=0, sticky=N+S+E+W)
        #Give the grid, column of the frame weight...
        Grid.rowconfigure(master, 0, weight=1)
        Grid.columnconfigure(master, 0, weight=1)
        self.create_widgets()

    def create_widgets(self):
        #Give the grid, column of each widget weight...
        for rows in xrange(3):
            Grid.rowconfigure(self, rows, weight=1)
        for columns in xrange(1):
            Grid.columnconfigure(self, columns, weight=1)

        self.label = Label(self, text="This is a test")
        self.label.grid(row=0, column=0, sticky=N+S+E+W)

        self.mytext1 = Text(self, width=30, height=5)
        self.mytext1.grid(row=1, column=0, sticky=N+S+E+W)

        self.mytext2 = Text(self, width=30, height=5)
        self.mytext2.grid(row=2, column=0, sticky=N+S+E+W)


root = Tk()
app = MyFrame(root)
root.mainloop()

Your basic frame looks like this:

from Tkinter import *

#Sets up a frame
class MyApplication(Frame):

    #When a class is initialized, this is called as per any class 
    def __init__(self, master):

        #Similar to saying MyFrame = Frame(master)
        Frame.__init__(self, master)

        #Puts the frame on a grid. If you had two frames on one window, you would do the row, column keywords (or not...)
        self.grid()

        #Function to put the widgets on the frame. Can have any name!
        self.create_widgets()

    def create_widgets(self):
        label = Label(self, text='Hello World!')
        label.grid()

        button = Button(self, text='Press Me!', command=self.hello)
        button.grid()

   def hello(self):
        print "Hello World!"

root = Tk()
app = MyApplication(root)
root.mainloop()

Any Tkinter widget can be treated like this allowing for templates (I had a program where I needed multiple entries with the same behavior (click on clears the default text, click off returns it if nothing was entered) and instead of adding the bindings to each one, I was able to create a class of entries that acted the same) and easy implementation of toplevels (additional windows). Here is an example of a more complex program:

class IntroScreen(Frame):
    def __init__(self, master):
        Frame.__init__(self, master)
        self.grid()
        self.title('Intro Screen')
        self.create_widgets()
        self.focus_force()

    def create_widgets(self):
        label = Label(self, text='Hello World!')
        label.grid()

        button = Button(self, text='Open Window', command=self.newWindow)
        button.grid()

   def newWindow(self):
        self.toplevel = InfoWindow()

#Like the frame, or any widget, this inherited from the parent widget
class InfoWindow(Toplevel):
    def __init__(self):
        Toplevel.__init__(self)
        self.grid()
        self.create_widgets()
        self.focus_force()

    def create_widgets(self):
        label = Label(self, text='This is a window!')
        label.grid()

root = Tk()
app = IntroScreen(root)
root.mainloop()

As you can see, this has added functionality that would be much more difficult without classes. Look for more answers on stackoverflow (I recommend Bryan Oakley's numerous and informative answers) and do some research online if you intend on going further into Tkinter's powerful functionality!

PS: Here's a good place to start: Switch between two frames in tkinter

Community
  • 1
  • 1
Al.Sal
  • 984
  • 8
  • 19
  • Is it possible to do this without putting the GUI into a class? – CodingCat Aug 16 '13 at 08:33
  • @Lastalda I would seriously consider working with classes in Tkinter. It is extremely difficult to make anything but a small sample GUI without the added functionality and ease of organization. I have edited my answer with some examples to get you started if you are so inclined. – Al.Sal Aug 16 '13 at 12:54
2

Here is the same as above without using a class. Using a class is cleaner and makes more sense as your program increases in size. Note that I set the weight of the label to 0, which prevents it from expanding. You don't have to do this as it is the default option. This is just to give you an idea of what you can do.

Some more details on grid layout manager: http://www.tkdocs.com/tutorial/grid.html

from Tkinter import *

master = Tk()

Label(master, text="This is a test").grid(row=0, column=0)

mytext1 = Text(master, width=30,height=5)
mytext1.grid(row=1, column=0, sticky="nsew")

mytext2 = Text(master, width=30,height=5)
mytext2.grid(row=2, column=0, sticky="nsew")

master.columnconfigure(0, weight=1)
master.rowconfigure(0, weight=0) # not needed, this is the default behavior
master.rowconfigure(1, weight=1)
master.rowconfigure(2, weight=1)

master.mainloop()
tylerjw
  • 802
  • 4
  • 14
  • 28
  • Thanks a lot! I know using a class for the GUI is supposed to be easier, but it confuses the hell out of me. – CodingCat Aug 16 '13 at 10:27
  • 1
    To understand the use of classes with Tkinter you need to have a good grasp on inheritance. However, I think for examples of how to do things in Tkinter non-class examples are cleaner and easier to read. You weren't asking how to develop a large application with Tkinter, just how to do one simple thing. The simpler the answer the better because it shows just what you asked, nothing more. – tylerjw Aug 16 '13 at 13:51