Tkinter框架切换触发AttributeError:loginScreen无frames属性求助
Ah, I see the issue here! The error is happening because your loginScreen class doesn't have a frames attribute—and it shouldn't, because that dictionary is supposed to live in your main mainActivity class. Let's break down what's missing and how to fix it.
First, let's recap the standard frame-switching pattern from that tutorial: your main app (mainActivity) holds a container frame, and a dictionary (frames) that stores instances of each of your screens (login, register). The showFrame method belongs to the main app, since it's responsible for managing all frames.
Step 1: Fix the mainActivity class to initialize the frames dictionary and showFrame method
You need to complete the __init__ method of mainActivity to create and store your frames, then add the showFrame method:
from tkinter import Tk, Frame, Button, Entry, Label class mainActivity(Tk): def __init__(self, *args, **kwargs): Tk.__init__(self, *args, **kwargs) self.title("Login/Register Demo") # Create the container frame that holds all screens container = Frame(self) container.pack(side="top", fill="both", expand=True) container.grid_rowconfigure(0, weight=1) container.grid_columnconfigure(0, weight=1) # Initialize the frames dictionary to store screen instances self.frames = {} # Create instances of each screen and add to the frames dict for ScreenClass in (loginScreen, registerScreen): frame = ScreenClass(container, self) # Pass main app as parent self.frames[ScreenClass] = frame frame.grid(row=0, column=0, sticky="nsew") # Show the login screen by default self.showFrame(loginScreen) def showFrame(self, pageClass): # Raise the requested frame to the top frame = self.frames[pageClass] frame.tkraise()
Step 2: Update your loginScreen class to reference the main app
Your loginScreen needs to keep a reference to the main mainActivity instance so it can call showFrame. When you create the login button, use that parent reference instead of trying to access self.frames directly:
class loginScreen(Frame): def __init__(self, parent, controller): Frame.__init__(self, parent) self.controller = controller # Store reference to main app # Add your login widgets here Label(self, text="Login Screen").pack(pady=10) Entry(self, placeholder="Username").pack(pady=5) Entry(self, placeholder="Password", show="*").pack(pady=5) # Button to switch to register screen Button(self, text="Go to Register", command=lambda: self.controller.showFrame(registerScreen)).pack(pady=10)
Step 3: Add the registerScreen class (for completeness)
Make sure your register screen follows the same pattern, so it can switch back to login:
class registerScreen(Frame): def __init__(self, parent, controller): Frame.__init__(self, parent) self.controller = controller Label(self, text="Register Screen").pack(pady=10) Entry(self, placeholder="Username").pack(pady=5) Entry(self, placeholder="Password", show="*").pack(pady=5) Entry(self, placeholder="Confirm Password", show="*").pack(pady=5) Button(self, text="Go to Login", command=lambda: self.controller.showFrame(loginScreen)).pack(pady=10)
Why this fixes your error:
- The
framesdictionary is now properly initialized inmainActivity, where it belongs. - Each screen (
loginScreen,registerScreen) receives a reference to the main app (controller), so when you click the button, you're callingcontroller.showFrame()instead of trying to accessself.frameson the screen itself. - The
showFramemethod correctly looks up the frame from the main app'sframesdict and raises it.
If you were previously defining showFrame inside loginScreen, that's where the mistake was—this method should live in the main app that manages all frames.
内容的提问来源于stack exchange,提问作者Ben Nettleship

