Search code examples
pythontkinterlayout

Switching between differently sized Frames


How can I make these pages two different sizes? Say I want to make StartPage large, 500 x 500, and New_Card_Page small, say 100 x 100. App.geometry("200x200") changes all pages, which is not what I want.

from tkinter import *
from tkinter import ttk
LARGE_FONT=('Verdana', 12)

class Index_Cards_App(Tk):   
    def __init__(self, *args, **kwargs):
        Tk.__init__(self, *args, **kwargs)
        container = 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, New_Card_Page):
            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")
        self.show_frame(StartPage)
    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()     
        
class StartPage(Frame):
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        label=Label(self, text='Index Cards')  
        label.pack(pady=10,padx=10)               
        button1 = ttk.Button(self, text='Enter New Card', command=lambda: controller.show_frame(New_Card_Page))
        button1.pack()      
        
class New_Card_Page(Frame): 
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        label=ttk.Label(self, text='Enter New Card') 
        label.pack(pady=10,padx=10)          
        button1 = ttk.Button(self, text='Back to Home', command=lambda: controller.show_frame(StartPage)).pack() 
        
app=Index_Cards_App()
app.geometry("200x200")
app.mainloop()       

Solution

  • The code you copied works by stacking all of the pages on top of each other, and assumes they are all the same size. It's not exactly a great design, especially if you're just learning tkinter.

    If you want each page to have its own size, the easiest solution is to remove the use of grid when the pages are initially created, and instead have show_frame remove the current page and add the new page.

    First, create an attribute to hold the current page so that it can be removed, and remove the call to grid inside the loop in __init__. Also, since we're not going to rely on stacking the pages on top of each other we can remove commands to configure the grid.

    def __init__(self, *args, **kwargs):
        Tk.__init__(self, *args, **kwargs)
        container = Frame(self)
        container.pack(side='top', fill='both', expand=True)
        self.current_frame = None
        self.frames = {}
        for F in (StartPage, New_Card_Page):
            frame = F(container, self)
            self.frames[F] = frame
        self.show_frame(StartPage)
    

    Next, modify show_frame to hide the current page and show the new page. Since we're no longer stacking widgets on top of each other, pack is a simpler choice than grid:

    def show_frame(self, cont):
        if self.current_frame is not None:
            self.current_frame.pack_forget()
        self.current_frame = self.frames[cont]
        self.current_frame.pack(fill="both", expand=True)
    

    Finally, remove the call to geometry at the end of your code, since that forces the window to a specific size.

    With those changes, each page will cause the window to resize to fit the current page.