I've been stuck for few days trying to figure out how I can resize the frame in TKInter dynamically using this approach.

class SampleApp(tk.Tk):


    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        # the container is where we'll stack a bunch of frames
        # on top of each other, then the one we want visible
        # will be raised above the others
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}
        for F in (StartPage, PageOne, PageTwo):
            page_name = F.__name__
            frame = F(container, self)
            self.frames[page_name] = frame

            # put all of the pages in the same location;
            # the one on the top of the stacking order
            # will be the one that is visible.
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame("StartPage")

    def show_frame(self, page_name):
        '''Show a frame for the given page name'''
        frame = self.frames[page_name]
        frame.tkraise()


class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="This is the start page", font=TITLE_FONT)
        label.pack(side="top", fill="x", pady=10)

        button1 = tk.Button(self, text="Go to Page One",
                            command=lambda: controller.show_frame("PageOne"))
        button2 = tk.Button(self, text="Go to Page Two",
                            command=lambda: controller.show_frame("PageTwo"))
        button1.pack()
        button2.pack()


class PageOne(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="This is page 1", font=TITLE_FONT)
        label.pack(side="top", fill="x", pady=10)
        button = tk.Button(self, text="Go to the start page",
                           command=lambda: controller.show_frame("StartPage"))
        button.pack()


class PageTwo(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="This is page 2", font=TITLE_FONT)
        label.pack(side="top", fill="x", pady=10)
        button = tk.Button(self, text="Go to the start page",
                           command=lambda: controller.show_frame("StartPage"))
        button.pack()


if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

I copied this code from Switch between two frames in tkinter, because I'm following the same approach.

The problem which I'm facing is that using this approach all frames are stacked in a container and the size of this container is the size of its' largest frame. Moving from one frame to another doesn't resize the respective window dynamically and leads to huge free space in small frames. I tried different techniques to make all frames in the container dynamically resizable but without much success. Can somebody suggest what I can do?


Instead of stacking the frames, make sure only one is ever managed by grid at a time. You can do this by calling grid_remove() of the current frame and then grid() on the new frame. Or, being lazy you can call grid_remove() on everything so that you don't have to remember which page is current.

def show_frame(self, page_name):
    '''Show a frame for the given page name'''
    for frame in self.frames.values():
        frame.grid_remove()
    frame = self.frames[page_name]
    frame.grid()

Note: the automatic resizing will stop working if you give the main window a fixed size with the geometry method on the root window, or if the user manually resizes the window. This is because tkinter assumes that if something explicitly requests a window size, that size should be honored.

If you always want the window to resize, you should reset the geometry to an empty string. You can add this as the last statement in the show_frame method:

frame.winfo_toplevel().geometry("")