-2

I am a beginner in python. I have a problem with using variable in different class. Please help. Here is the sample code from Using buttons in Tkinter to navigate to different pages of the application?

import Tkinter as tk

class Page(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)
    def show(self):
        self.lift()

class Page1(Page):
   def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)
       label = tk.Label(self, text="This is page 1")
       label.pack(side="top", fill="both", expand=True)

       entry = tk.Entry(self)
       entry.pack()

class Page2(Page):
   def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)
       label = tk.Label(self, text="This is page 2")
       label.pack(side="top", fill="both", expand=True)

       text = tk.Text(self, entry.get())
       root.after(...)

class MainView(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)
        p1 = Page1(self)
        p2 = Page2(self)


        buttonframe = tk.Frame(self)
        container = tk.Frame(self)
        buttonframe.pack(side="top", fill="x", expand=False)
        container.pack(side="top", fill="both", expand=True)

        p1.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
        p2.place(in_=container, x=0, y=0, relwidth=1, relheight=1)


        b1 = tk.Button(buttonframe, text="Page 1", command=p1.lift)
        b2 = tk.Button(buttonframe, text="Page 2", command=p2.lift)


        b1.pack(side="left")
        b2.pack(side="left")


        p1.show()

if __name__ == "__main__":
    root = tk.Tk()
    main = MainView(root)
    main.pack(side="top", fill="both", expand=True)
    root.wm_geometry("400x400")
    root.mainloop()

Then it have two problems:

 NameError: global name 'entry' is not defined
 NameError: global name 'root' is not defined

How can i use these variable? Please help!

Community
  • 1
  • 1
Ethan
  • 13
  • 2
  • Seems as if the import is not working correctly. Sure that the Tkinter is installed correctly? – Anna Jeanine Apr 13 '17 at 09:46
  • Why do need so many classes may I ask? In case of variable entry you have declared the variable in Page1 class and using it in Page2 class. This cant happen as the variables are bound to their classes. If you really wanna do so, declare entry as a class variable, so that you may access the same using Page1.entry. – DineshKumar Apr 13 '17 at 09:50
  • You really need to familiarize yourself with the concept of scopes and how they differ from fetching attributes. – GIZ Apr 13 '17 at 10:18
  • @DineshKumar: you, like the author, misunderstand the code. The code that this was copied from was designed to allow you to easily get the instance of any page from any other page. You don't want to use a class variable, you want to leverage the controller to get an instance of a page, and from the instance you can access the page attributes. See http://stackoverflow.com/q/33646605/7432 – Bryan Oakley Apr 14 '17 at 03:53
  • To better understand this code that you copied from a tutorial site, see http://stackoverflow.com/a/7557028/7432 – Bryan Oakley Apr 14 '17 at 03:58
  • @BryanOakley I see...thanks for clarifying. – DineshKumar Apr 14 '17 at 04:31

1 Answers1

-1

You're defining the variable entry inside the body of a method, this does not make entry accessible to the global scope, this is how you should embed objects:

class Page1(Page):
   def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)
       self.label = tk.Label(self, text="This is page 1")
       self.label.pack(side="top", fill="both", expand=True)

       self.entry = tk.Entry(self)
       self.entry.pack()

As you can see, you embed label and entry objects to self, the implied instance of class Page1 when you call class Page1(). Any variable assigned inside a body of a method or a function becomes local to that method or function. That's how you should go with your code.

Familiarize yourself with this concept: Short Description of Python Scoping Rules

Edit:

In class Page2 If you really want to access self.entry.get of class Page1, then you need to pass the object of class Page1 to the constructor of class Page2 and then fetch the entry from the object you passed to Page2.__init__ like the following:

class Page2(Page):
   def __init__(self, page1_obj, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)
       self.label = tk.Label(self, text="This is page 2")
       self.label.pack(side="top", fill="both", expand=True)

       self.text = tk.Text(self, page1_obj.entry.get())  # access attributes of the passed-in object (page1._object)
       root.after(...)

Here you must pass an object to the constructor and then you'll be able to access the object's attributes including its bound methods. The reason why I did this though is because in your Page1 class you passed self to tk.Entry so I thought you probably wanted to use the returned results of self.entry = tk.Entry(self)of Page1. If you don't really intend to use the returned results of self.entry = tk.Entry(self) of Page1 class then you can add the same assignment in the constructor of Page2: self.entry = tk.Entry(self).

GIZ
  • 4,409
  • 1
  • 24
  • 43
  • thx for answer. but how can i use self.entry.get() in class2? – Ethan Apr 13 '17 at 12:02
  • @Ethan I edited my answer for your question. See the edited portion under the title **Edit**. I hope I understood your question. – GIZ Apr 13 '17 at 12:51
  • THANKS FOR YOUR ANSWER!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX – Ethan Apr 13 '17 at 13:55
  • **No**, you do _not_ need to pass the object of Page1 to the constructor of Page2. This architecture was designed so that any "page" could get the instance of any other "page" via the controller. Passing objects between the classes is completely unnecessary with this design. – Bryan Oakley Apr 14 '17 at 03:54
  • @BryanOakley If you read the last paragraph in my answer you'll understand why I did that. OP wanted the result of `self.entry = tk.Entry(self)` of `Page1` in `Page2`. In my answer I said: _If you don't really intend to use the returned results of `self.entry = tk.Entry(self)` of `Page1` class then you can add the same assignment in the constructor of `Page2`: `self.entry = tk.Entry(self)`_ And yes, if I'm not mistaken, OP wanted to have an access to the instance essentially. ` tk.Entry(self)` uses `self` and hence the instance is needed. So I thought OP needs an access to a bound method. – GIZ Apr 14 '17 at 08:04