How to access variables from different classes in tkinter?

I searched a lot and I still don’t know how the access variable from different classes in Python has been ... in this case I want to access the self.v variable from the PageOne class to the PageTwo class .. please help me

Here is my code ...

 import tkinter as tk import smtplib TITLE_FONT = ("Helvetica", 18, "bold") class SampleApp(tk.Tk): def __init__(self): tk.Tk.__init__(self) container = tk.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 (StartPage, PageOne, PageTwo): frame = F(container, self) self.frames[F] = frame frame.grid(row=0, column=0, sticky="nsew") self.show_frame(StartPage) def show_frame(self, c): frame = self.frames[c] frame.tkraise() class StartPage(tk.Frame): def __init__(self, parent, controller): tk.Frame.__init__(self, parent) label = tk.Label(self, text="PyMail",foreground = "Red", font=("Courier", 30, "bold")) label.pack(side="top") sublabel = tk.Label(self, text="Bringing you the\n the easiest way of communication", font=("Courier", 15)) sublabel.pack() wallpaper = tk.PhotoImage(file='Python-logo-notext.gif') img = tk.Label(self, image=wallpaper) img.image = wallpaper img.pack(side="top", expand = True) button1 = tk.Button(self, text="Click Here to Login to your account",fg="red", command=lambda: controller.show_frame(PageOne)) button2 = tk.Button(self, text="Go to Page Two", command=lambda: controller.show_frame(PageTwo)) button2.pack(side="bottom") button1.pack(side="bottom") class PageOne(tk.Frame): def __init__(self, parent, controller): tk.Frame.__init__(self, parent) self.controller=controller label = tk.Label(self, text="Personal Information", font=TITLE_FONT, foreground="blue") label.pack(side="top", fill="x", pady=10) global optionv self.optionv = tk.StringVar() self.optionv.set("---Select One---") optionm = tk.OptionMenu(self, self.optionv, "---Select One---", "@gmail.com", "@yahoo.com", "@hotmail.com") t1 = tk.Label(self, text="Email Account: ") self.v = tk.StringVar() self.v.set("") entry1 = tk.Entry(self, textvariable=self.v) t2 = tk.Label(self,text="\nPassword: ") self.pwd = tk.StringVar() self.pwd.set("") entry2 = tk.Entry(self, textvariable=self.pwd) entry2.config(show="*") lgbutton=tk.Button(self, text="Log In", command=self.login) button = tk.Button(self, text="Go to the start page", command=lambda: controller.show_frame(StartPage)) #final = tk.Label(self, textvariable=self.v) #finalpwd = tk.Label(self, textvariable=self.pwd) t1.pack() entry1.pack() optionm.pack() t2.pack() entry2.pack() #final.pack() #finalpwd.pack() lgbutton.pack() button.pack(side="bottom") def login(self): value = tk.Label(self, text="Invalid username / password", font=("Courier", 15, "bold"), foreground="red") success = tk.Label(self, text="Login was Successful \n (Click ""Continue"" to compose email)", font=("Courier", 15, "bold"), foreground="blue") cbutton = tk.Button(self, text="Continue", command=lambda: self.controller.show_frame(PageTwo)) status = tk.Label(self, text="Please select your email domain", foreground="red") if self.optionv.get() == "@gmail.com": try: global server server = smtplib.SMTP("smtp.gmail.com", 587) server.ehlo() server.starttls() server.login(self.v.get()+self.optionv.get(), self.pwd.get()) success.pack() cbutton.pack(side="bottom") except: value.pack() elif self.optionv.get() == "@yahoo.com": try: server = smtplib.SMTP("smtp.yahoo.com", 587) server.ehlo() server.starttls() server.login(self.v.get()+self.optionv.get(), self.pwd.get()) success.pack() cbutton.pack(side="bottom") except: value.pack() elif self.optionv.get() == "@hotmail.com": try: server = smtplib.SMTP("smtp.live.com", 587) server.ehlo() server.starttls() server.login(self.v.get()+self.optionv.get(), self.pwd.get()) success.pack() cbutton.pack(side="bottom") except: value.pack() else: status.pack() class PageTwo(tk.Frame): def __init__(self, parent, controller): tk.Frame.__init__(self, parent) label = tk.Label(self, text="Compose Mail", font=TITLE_FONT, foreground="green") label.pack(side="top", fill="x", pady=10) self.reciever = tk.StringVar() self.reciever.set("") senderl = tk.Label(self, text="Send to: ") rmail = tk.Entry(self, textvariable=self.reciever) self.senderoption = tk.StringVar() self.senderoption.set("---Select One---") senderdomain = tk.OptionMenu(self, self.senderoption, "---Select One---", "@gmail.com", "@hotmail.com", "@yahoo.com") self.mail = tk.StringVar() self.mail.set("") self.textw = tk.Entry(self, textvariable=self.mail) button = tk.Button(self, text="Go to the start page", command=lambda: controller.show_frame(StartPage)) sendbutton = tk.Button(self, text = "Send Mail", command=self.sendmail) senderl.pack(side="top", anchor="w") rmail.pack(side="top", anchor="nw") senderdomain.pack(side="top", anchor="nw") self.textw.pack(fill="both") button.pack(side="bottom") sendbutton.pack(side="bottom") def sendmail(self): sent = tk.Label(self, text="Email has been sent") if self.senderoption.get() == "@gmail.com": try: server.sendmail(self.v.get()+self.optionv.get(), self.reciever.get()+self.senderoption.get(), "YES") print("Success") sent.pack() except: print("Unsuccesful") print(PageOne.self.v.get()) if __name__ == "__main__": app = SampleApp() app.title("PyMail") app.geometry("400x400") app.mainloop() 
+5
python user-interface tkinter smtplib
Nov 11 '15 at 8:20
source share
2 answers

Essentially, your question has a simple answer. "How to get value from object X?" The answer is the same for any object: you get it by setting object X. All you need for this is to get a link to the object, and then directly access the attribute.

Access data from other pages

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

So how do you get the link? The code (which you copied either from the tutorial, or from https://stackoverflow.com/a/1686411/) that was copied from the tutorial) was designed to make this easy. Each page is given a link to the controller, and this controller has a link to each page. Therefore, you can ask the controller to give you a link to the page.

The first step is to save the link to the controller in each class. Interestingly, you are already doing this in PageOne , but you have to do this on all pages. Make sure you add self.controller = controller to each __init__ method, for example:

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

Then we need to add a method to the controller class, which will return a link 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 any "page" you can access the object for any other "page". For example, in PageTwo you can access the variable v from PageOne as follows:

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

Using shared data

An even better solution for your SampleApp class to create a single set of variables that share all pages. You can create a dictionary in this class, and then use the controller to access each page. 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 any class you can access the following data:

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

The reason this is the best solution is because your pages do not need to know how other pages are implemented. When a page uses the exact implementation of another page, this is called a hard link. If the pages do not need to know how other pages are implemented, this is called free communication.

Free communication gives you great flexibility. Instead of each page being closely related to every other page, they are all closely related to one object: the controller. As long as each page only knows about the controller, each page can be changed at any time without affecting the rest of the program.

Of course, if you change the controller, you must change all the pages, but if you are good at designing a controller that is less likely to happen and will be easier to manage when that happens.

+19
Nov 11 '15 at 12:26
source share

This is due to the global frame.

If you create a variable inside a class, it will exist only inside this function. If you want to "transfer" a variable inside a class (or function, for that matter) into a global frame, you use a global one .

 class firstClass(): global my_var_first my_var_first = "first variable" print(my_var_first) # This will work, because the var is in the global frame class secondClass(): my_var_second = "second variable" print(my_var_first) # This will work, as the var is in the global frame and not defined in the class print(my_var_second) # This won't work, because there is no my_var_second in the global frame 

You can use pythontutor to visualize memory, as it will show you step by step how memory is created.

I hope I can help you!

EDIT

I think I should add that if you define a variable inside the class / function with the same name as the variable in the global frame, it will not delete the global variable. Instead, it will create a new one (with the same name) in its own frame. A class or function will always use a variable in its own frame, if available.

 x = 5 def print_variable(): x = 3 print(x) print(x) print_variable() # OUTPUT: # 5 # 3 
-one
Nov 11 '15 at 9:20
source share



All Articles