How to access variables from different classes in tkinter?

Solution 1:

At its core, your question has a simple answer. "How do I get a value from object X?" The answer is the same for any object: you get it by asking object X. All you need in order to do that is get a reference to the object and then access the attribute directly.

Accessing data from other pages

In your case, the code in PageTwo needs a reference to PageOne so you can get the v variable.

So, how do you get a reference? The code (which you copied either from a tutorial, or from the stackoverflow answer that the tutorial copied from) was designed to make this easy. Each page is given a reference to a controller, and this controller has a reference to each page. You can therefore ask the controller to give you a reference to a page.

The first step is to save the reference to the controller in each class. Interestingly, you're already doing this in PageOne, but you should do it in all the pages. Make sure you add self.controller = controller in every __init__ method, like so:

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

Next, we need to add a method in the controller class that will return a reference to the page. Add the following function to SampleApp:

class SampleApp(tk.Tk):
    ...
    def get_page(self, page_class):
        return self.frames[page_class]
    ...

Now, from within any "page" you can get access to the object for any other "page". For example, in PageTwo you can access the v variable from PageOne like this:

page1 = self.controller.get_page(PageOne)
page1.v.set("Hello, world")

Using shared data

An even better solution is for your SampleApp class to create a single set of variables that all of the pages share. You can create a dictionary in that class, and then use the controller to give every page access. For example:

class SampleApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.shared_data = {
            "username": tk.StringVar(),
            "password": tk.StringVar(),
            ...
        )

Then, from within any class you can access the data like this:

entry1 = tk.Entry(self, textvariable=self.controller.shared_data["username"])
...
username = self.controller.shared_data["username"].get()

The reason this is the better solution is that your pages don't have to know how the other pages are implemented. When a page relies on the exact implementation of another page this is called tight coupling. If the pages don't need to know how the other pages are implemented, this is called loose coupling.

Loose coupling gives you more flexibility. Instead of having every page tightly coupled to every other page, they are all tightly coupled to a single object: the controller. As long as every page knows only about the controller, each page is free to be changed at any time without affecting the rest of the program.

Of course, if you change the controller you have to change all of the pages, but if you do a good job designing the controller that's less likely to occur and easier to manage when it does occur.