0

I have been working to improve my Tkinter skills through a combination of books, on-line tutorials, and utilizing questions and examples from this site. In one script I am working to understand and build upon this question and popular answer: Switch between two frames in tkinter. I have created a version that allows the creation of multiple instances of the pages, tracks the number of time page 1 has been selected for each instance, and updates the label for page 1 with the number of times page 1 has been selected. To reduce the size of the program the code shown is only for the updating of the page 1 label. I have only been able to accomplish this through the use of a global variable in the 'PageOne' object and the method that is called to show it. I feel there must be a better way but all of the ways I tried yields an error similar to : #AttributeError: '_tkinter.tkapp' object has no attribute 'label'. Should be simple I thought but I spent a couple of days on this issue alone.


import tkinter as tk                
from tkinter import font as tkfont  
'''
original post
https://stackoverflow.com/questions/7546050/switch-between-two-frames-in-tkinter
'''


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.Label1_Text = tk.StringVar()
        self.PageOne_Ct = tk.IntVar()
        #-------------------------------
        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 get_lbl_text(self):
        label1text = self.Label1_Text.get()
        return label1text

    def get_page1_cts(self):
        counts = self.PageOne_Ct.get() 
        return counts     

    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: PageOne.Show_PageOne(self, 
                            parent, controller))
        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)
        global label
        self.controller = controller
        label = tk.Label(self, text = self.controller.Label1_Text.get(),
                              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()

    def Show_PageOne(self, parent, controller):
        
        global label   
        count = self.controller.get_page1_cts()
        self.controller = controller
        count = self.controller.PageOne_Ct.get()
        count += 1
        self.controller.PageOne_Ct.set(count)
        new_label1_text = "You have clicked page one {} times".format(count)
        self.controller.Label1_Text.set(new_label1_text)
        label.configure(text=new_label1_text)
        controller.show_frame("PageOne")

class PageTwo(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label2 = tk.Label(self, text="This is page 2", font=controller.title_font)
        label2.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()
BillinKY
  • 1
  • 3

1 Answers1

0

Here is an example that doesn't require passing a bunch of vars around.

import tkinter as tk


'''
    PREVIOUS|NEXT DISPLAY FOR PAGES
'''
class Book:
    def __init__(self, master, pages):
        #init page vars
        self.pnum  = 0 
        self.pages = pages
        self.page  = self.pages[self.pnum].show()
        
        #next/prev buttons
        tk.Button(master, text='prev', command=self.prev).place(relx=.05, rely=.95, anchor='center')
        tk.Button(master, text='next', command=self.next).place(relx=.95, rely=.95, anchor='center')
        
    def next(self):
        self.page.hide()
        self.pnum = (self.pnum+1)%len(self.pages)
        self.page = self.pages[self.pnum].show()
        
    def prev(self):
        self.page.hide()
        self.pnum = range(len(self.pages))[self.pnum-1]
        self.page = self.pages[self.pnum].show()


'''
    GENERIC PAGE FOR ALL PAGES TO INHERIT FROM
'''
class Page(tk.Frame):
    def __init__(self, master, **kwargs):
        tk.Frame.__init__(self, master, **kwargs)
        self.visits = 0
        self.label = tk.Label(self, text=f'visits: {self.visits}', font='consolas 16 bold', fg='white', bg=self['bg'])
        self.label.grid()
        
    def show(self) -> tk.Frame:
        self.visits += 1
        self.label.configure(text=f'visits: {self.visits}')
        self.grid(row=0, column=0, sticky='nswe')
        return self
        
    def hide(self):
        self.grid_forget()
        
        
'''
    EXAMPLE PAGES
'''        
class Page_1(Page):
    def __init__(self, master, **kwargs):
        Page.__init__(self, master, **kwargs)
        
     
class Page_2(Page):
    def __init__(self, master, **kwargs):
        Page.__init__(self, master, **kwargs)
    

class Page_3(Page):
    def __init__(self, master, **kwargs):
        Page.__init__(self, master, **kwargs)
        
        
'''
    ROOT
'''
class Root(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.title("Pages Example")
        self.geometry('800x600+100+100')
        
        #make the page span the entire display
        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(0, weight=1)
        
        #create book
        Book(self, [Page_1(self, bg='blue') , 
                    Page_2(self, bg='red')  , 
                    Page_3(self, bg='green'),
                   ])
        
        self.mainloop()
        

Root() if __name__ == "__main__" else None
    
OneMadGypsy
  • 4,640
  • 3
  • 10
  • 26