why is label "lorem" of sub-frame of page One is being displayed on start page?

56 Views Asked by At

I am following the answer of this: Switch between two frames in tkinter

in the below mentioned code, I am making form with two pages, start page and page one, the question is that why is label "lorem" of sub-frame of page One is being displayed on start page, since it's a part of sub frame of page one?

import tkinter as tk                # python 3
from tkinter import font as tkfont  # python 3

class SampleApp(tk.Tk):

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

        self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")

        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):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame

            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=controller.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=controller.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()

        frame1 = tk.Frame(self).pack()
        tk.Label(frame1, text='lorem', font=controller.title_font).pack()


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

2

There are 2 best solutions below

3
On

'frame1' seems to be unbounded from the local scope of PageOne. I've looked at it for a while, and think it's due to that for F in... loop just setting parent=container for all frames, where container is the root window.

If you specify PageOne's self as the parent of label, instead of frame1, then it displays OK.

#! /usr/bin/env python3

import tkinter as tk
from tkinter import font as tkfont  ## python 3

class SampleApp( tk .Tk ):

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

        self .title_font = tkfont .Font( family='Helvetica',  size=18,  weight='bold',  slant='italic' )

        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( parent=container,  controller=self )
            self .frames[ page_name ]  = frame
            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
        tk .Label( self,  text='This is the start page',  font=controller .title_font ) .pack( side='top',  fill='x',  pady=10 )
        tk .Button( self,  text='Go to Page One',  command=lambda: controller .show_frame('PageOne') ) .pack()
        tk .Button( self,  text='Go to Page Two',  command=lambda: controller .show_frame('PageTwo') ) .pack()


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


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


if __name__ == '__main__':
    app  = SampleApp()
    app .mainloop()
0
On

the problem is solved by packing the "frame1" in the next line e.g:

        frame1 = tk.Frame(self)
        frame1.pack()

now the contents of "frame1" display only in "frame1" not on other frames.