Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tkinter Frame Resize

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?

like image 980
user134 Avatar asked Mar 14 '16 15:03

user134


People also ask

How do I change frame size in Tkinter?

The frame widget in Tkinter works like a container where we can place widgets and all the other GUI components. To change the frame width dynamically, we can use the configure() method and define the width property in it.

Can you resize an image in Tkinter?

Build A Paint Program With TKinter and Python We can use Pillow to open the images, resize them and display in the window. To resize the image, we can use image_resize((width, height) **options) method. The resized image can later be processed and displayed through the label widget.


1 Answers

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("")
like image 161
Bryan Oakley Avatar answered Sep 30 '22 05:09

Bryan Oakley