-1

Using the method suggested in Switch between two frames in tkinter I have tried to switch between a login frame and a register frame. Nevertheless, when showFrame(register) is called after the register button is pressed on the login screen, an attribute error occurs:

(frame=self.frames[pageName]; AttributeError:'loginScreen' object has no 
attribute 'frames')



class mainActivity(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 (loginScreen, register):
            frame = F(container, self)
            self.frames[F]=frame
            frame.grid(row=0, column=0, sticky="snew")

        self.showFrame(loginScreen)

    def showFrame(self, pageName):
        frame=self.frames[pageName]
        frame.tkraise()



#-------------------------------------------------

class loginScreen(Frame):
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        self.controller=controller


        self.regBtn =Button(self, text="Register", command=self.regBtnClicked)
        self.regBtn.grid(row=2,column=1)

        self.grid()


    def regBtnClicked(self):
        mainActivity.showFrame(self, register)
        #send to register screen


#-------------------------------------------------

class register(Frame):
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        self.controller=controller

        self.grid(row=0, column=0)



        self.cancelBtn = Button(self, text="Cancel",command=self.cancelBtnClicked)
        self.cancelBtn.grid(row=4, column=1)




    def cancelBtnClicked(self):
        #return to login screen
        mainActivity.showFrame(self, loginScreen)


app = mainActivity()
app.mainloop()
  • 1
    Please provide [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve). This will allow us to assist you with you question. The code you have provide will not run without some guess work. – Mike - SMT Apr 04 '18 at 13:13
  • Well, does your `loginScreen` class have such an attribute? Python doesn't lie about this. Either you're trying to access that attribute on the wrong object, or you're trying to access it before it has been set. – Bryan Oakley Apr 04 '18 at 13:20
  • @Mike-SMT hopefully that is better? if not I can upload the entire code, thanks – Ben Nettleship Apr 04 '18 at 13:25

1 Answers1

1

There are several issues with your code. First you are missing an important potion of the for F in (loginScreen, register): for loop.

You need to have:

page_name = F.__name__

This is the line of code that is used to provide the string name for the key portion of the self.frames dictionary.

So instead of doing:

self.frames[F]=frame

Do this instead:

self.frames[page_name] = frame

Try to use the print statement while troubleshooting. All it took was for me to add print(self.frames) right before the error was occurring to have an idea of what is going wrong here.

You will also need to change self.showFrame(loginScreen) to self.showFrame("loginScreen") as well as any other call to showFrame() to reflect the same change.

Another issue you were having was this line:

mainActivity.showFrame(self, loginScreen)

You need to reference the controller instead here like this:

self.controller.showFrame("loginScreen")

You do not need self.grid(row=0, column=0) in your frame class's because these have already been set in your for loop. No need to do it again.

With all that take a look at the below code:

from tkinter import *

class mainActivity(Tk):
    def __init__(self, *args, **kwargs):
        Tk.__init__(self, *args, **kwargs)
        container=Frame(self)
        container.pack(side="top", fill="both", expand=True)
        self.frames={}

        for F in (loginScreen, register):
            page_name = F.__name__
            frame = F(container, self)
            self.frames[page_name] = frame
            frame.grid(row=0, column=0, sticky="snew")

        print(self.frames)
        self.showFrame("loginScreen")

    def showFrame(self, pageName):
        frame=self.frames[pageName]
        frame.tkraise()
#-------------------------------------------------
class loginScreen(Frame):
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        self.controller=controller
        self.regBtn = Button(self, text="Register", command=self.regBtnClicked)
        self.regBtn.grid(row=2,column=1)

    def regBtnClicked(self):
        self.controller.showFrame("register")
#-------------------------------------------------
class register(Frame):
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        self.controller=controller
        self.cancelBtn = Button(self, text="Cancel",command=self.cancelBtnClicked)
        self.cancelBtn.grid(row=4, column=1)

    def cancelBtnClicked(self):
        self.controller.showFrame("loginScreen")


app = mainActivity()
app.mainloop()
Mike - SMT
  • 14,784
  • 4
  • 35
  • 79