1

I am simply trying to move class ScreenThree to a separate file 9 I will soon have many more)....However for the lambdas I get nameError ...how to fix?

I've tried many arrangements, but allways get some sort of nameError. For this post, I have deleted ScreenTwo, since these basically all look the same. When moving this class to its own file what needs to be changed? I used import, which seemed to work & screen3 shows. , However the button lambda is where it fails import tkinter as tk

LARGE_FONT = ("Verdana", 12) # font's family is Verdana, font's size is 12 

class MainWindow(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.title("Fuzzy System") # set the title of the main window
        self.geometry("300x300") # set size of the main window to 300x300 pixels

        # this container contains all the screens
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)   # make the cell in grid cover the entire window
        container.grid_columnconfigure(0,weight=1) # make the cell in grid cover the entire window
        self.frames = {} # these are screens we want to navigate to

        for F in (ScreenOne, ScreenTwo,ScreenThree): # for each screen
            frame = F(container, self) # create the screen
            self.frames[F] = frame  # store into frames
            frame.grid(row=0, column=0, sticky="nsew") # grid it to container

        self.show_frame(ScreenOne) # let the first screen is ScreenOne

    def show_frame(self, name):
        frame = self.frames[name]
        frame.tkraise()

class ScreenOne(tk.Frame):
    def __init__(self, parent, controller):
        self.controller=controller
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text='This is ScreenOne', font=LARGE_FONT)
        label.pack(pady=10, padx=10) # center alignment
   # when click on this button, call the show_frame method to make screenOne appear
        button1 = tk.Button(self, text='Visit screen two', command=lambda : controller.show_frame(ScreenTwo))
        button1.pack() # pack it in
        self.button2 = tk.Button(self, text='GOTO Screen Three', command=lambda : controller.show_frame(ScreenThree))
        self.button2.place(relx=0.5, rely=0.29, height=41, width=144)
        self.button2.configure(background="#911218")

class ScreenThree(tk.Frame):
    def __init__(self, parent, controller):
        self.controller=controller
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text='This is screen Three', font=LARGE_FONT)
        label.pack(pady=10, padx=10)

        button1 = tk.Button(self, text='GOTO ScreenTwo', command=lambda : controller.show_frame(ScreenTwo))
        button1.pack()
        button2 = tk.Button(self, text='GOTO Screen One', command=lambda : controller.show_frame(ScreenOne))
        button2.pack()

if __name__ == '__main__':
    app = MainWindow()
    app.mainloop()


I have several classes, all looking similar to the following. They all work fine, no problems. However I want to move them to individual files, since they will soon become lengthy. I moved the following to file `scr3.py`.  
I then added the following to my main file:

    from scr3 import ScreenThree

Screen one and two work fine and my buttons in `screen3` show up.  However when pushing on the screen three buttons I get a `NameError: name 'ScreenOne' is not defined` and similar for `screen2` (see the lambda funcs).  These worked fine when all was in one file.  `Screen1` and `2` (still in the `main` file) continue to work fine.  
Why does it work fine when this same code is in the `main` file , but now fails? It has only been moved.  What is the workaround?

    import tkinter as tk
    LARGE_FONT = ("Verdana", 12) # font's family is Verdana, font's size is 12

    class ScreenThree(tk.Frame):

    def __init__(self, parent, controller):
        self.controller=controller
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text='This is screen Three', font=LARGE_FONT)
        label.pack(pady=10, padx=10)

        button1 = tk.Button(self, text='GOTO ScreenTwo', command=lambda : controller.show_frame(ScreenTwo))
        button1.pack()
        button2 = tk.Button(self, text='GOTO Screen One', command=lambda : controller.show_frame(ScreenOne))
        button2.pack()
Hoyt777
  • 17
  • 4
  • You should start with the code here: http://stackoverflow.com/questions/7546050 because it uses the class _name_ in `show_frame`, removing the need to import every class in every file. – Bryan Oakley Jul 06 '18 at 11:53
  • I tried separating the loop into separate lines, but then show_frame gets a _main_ key error – Hoyt777 Jul 06 '18 at 15:09
  • Hi Bryan ...I tried replacing the For loop with the separated lines of code, but then I get an error in show_frame : line 34, in show_frame frame = self.frames[name] KeyError: – Hoyt777 Jul 06 '18 at 18:36
  • The problem isn't the loop, and it's not even a tkinter problem. This is just basic python. Have you seen this? https://stackoverflow.com/questions/39530107/tkinter-have-code-for-pages-in-separate-files – Bryan Oakley Jul 06 '18 at 18:39

1 Answers1

0

The code of ScreenThree is no longer in the same namespace as e.g. ScreenOne. You might fix this by passing a reference to ScreenOne and ScreenTwo as arguments to the __init__.

Lutz Büch
  • 343
  • 4
  • 12
  • You might fix this by passing a reference to ScreenOne and ScreenTwo as arguments to the __init__. Not sure exactly what you mean/how. Is there a way to keep this in the same namespace? – Hoyt777 Jul 06 '18 at 07:15
  • `def __init__(self, parent, controller, ScreenOne, ScreenTwo):` – Lutz Büch Jul 06 '18 at 07:32
  • Thanks, though, that just generates a different error. Doesn't quite seem like a good approach, especially when there will be 20 screens. for F in (ScreenOne, ScreenTwo,screenThree): # for each screen frame = F(container, self) # create the screen NOW gives this error: frame = F(container, self) # create the screen TypeError: __init__() missing 2 required positional arguments: 'ScreenOne' and 'ScreenTwo' self.frames[F] = frame # store into frames frame.grid(row=0, column=0, sticky="nsew") # grid it to container – Hoyt777 Jul 06 '18 at 07:39