0

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()

jojo
  • 1
  • 1
    Try examining the value of `frame1` immediately before creating the "lorem" label. It's not what you're assuming it is. – Bryan Oakley Nov 24 '20 at 20:17
  • thanks @BryanOakley for your immediate response, furthermore, how can I examine it, and hope you understand the issue, which is, "lorem" is a label of "frame1" which is sub-frame of "page one" then why is "lorem" being displayed on start page? – jojo Nov 25 '20 at 05:19
  • You _think_ `frame1` is a sub-frame of "page one", but it is not set to the frame you created. It is on the start page because `frame1` is set to `None`. That's why I asked you to examine the value: you're assuming it set to something else. As for how you can examine it, a simple method is to add `print(frame1)` immediate after creating `frame1`. Or, learn how to use [pdb](https://docs.python.org/3/library/pdb.html) – Bryan Oakley Nov 25 '20 at 05:21
  • then how can i make new frame in page one? that should only be displayed in page one. thanks – jojo Nov 25 '20 at 05:48

2 Answers2

0

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.

jojo
  • 1
-1

'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()
Doyousketch2
  • 2,060
  • 1
  • 11
  • 11
  • `container` is not the root window, it is a frame inside the root window. – acw1668 Nov 25 '20 at 01:28
  • yea. Here's another very similar method -- https://www.delftstack.com/howto/python-tkinter/how-to-switch-frames-in-tkinter Using self as well there, instead of placing it on a new `tk.Frame()` instance. – Doyousketch2 Nov 25 '20 at 01:45
  • 1
    The issue is not what you describe in your answer. Think about the comment given by Bryan. – acw1668 Nov 25 '20 at 01:50