Wie kann man auf Variablen aus verschiedenen classn in tkinter zugreifen?

Ich habe viel gesucht und ich weiß immer noch nicht, wie Sie auf Variablen aus verschiedenen classn in Python zugreifen … in diesem Fall möchte ich auf die Variable self.v von PageOne class zu PageTwo class PageTwo .. bitte helfen Sie mir

Hier ist mein 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() 

Im core hat Ihre Frage eine einfache Antwort. “Wie bekomme ich einen Wert von Objekt X?” Die Antwort ist für jedes Objekt gleich: Sie erhalten es, indem Sie Objekt X fragen. Alles, was Sie dazu benötigen, ist, einen Verweis auf das Objekt zu erhalten und dann direkt auf das Attribut zuzugreifen.

Zugriff auf Daten von anderen Seiten

In Ihrem Fall benötigt der Code in PageTwo einen Verweis auf PageOne damit Sie die Variable v PageTwo können.

Also, wie bekommen Sie eine Referenz? Der Code (den Sie entweder aus einem Lernprogramm oder aus der Stackoverflow-Antwort kopiert haben, aus der das Tutorial kopiert wurde) wurde entwickelt, um dies zu vereinfachen. Jede Seite erhält einen Verweis auf einen Controller, und dieser Controller hat einen Verweis auf jede Seite. Sie können daher den Controller bitten, Ihnen einen Verweis auf eine Seite zu geben.

Der erste Schritt besteht darin, den Verweis auf den Controller in jeder class zu speichern. Interessanterweise machen Sie dies bereits in PageOne , aber Sie sollten es auf allen Seiten tun. self.controller = controller Sie sicher, dass Sie in jeder Methode __init__ self.controller = controller hinzufügen:

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

Als Nächstes müssen wir eine Methode in der Controller-class hinzufügen, die einen Verweis auf die Seite zurückgibt. Fügen Sie SampleApp die folgende function SampleApp :

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

Jetzt können Sie von jeder “Seite” aus auf das Objekt für jede andere “Seite” zugreifen. In PageTwo können Sie beispielsweise PageTwo auf die v Variable von PageOne zugreifen:

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

Gemeinsame Daten verwenden

Eine noch bessere Lösung besteht darin, dass Ihre SampleApp class einen einzelnen Satz von Variablen erstellt, die von allen Seiten gemeinsam genutzt werden. Sie können ein Wörterbuch in dieser class erstellen und dann den Controller verwenden, um jeder Seite Zugriff zu gewähren. Beispielsweise:

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

Dann können Sie innerhalb jeder class auf die Daten wie folgt zugreifen:

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

Der Grund dafür ist, dass Ihre Seiten nicht wissen müssen, wie die anderen Seiten implementiert sind. Wenn eine Seite auf die genaue Implementierung einer anderen Seite angewiesen ist, wird dies als enge Kopplung bezeichnet . Wenn die Seiten nicht wissen müssen, wie die anderen Seiten implementiert sind, wird dies als lose Kopplung bezeichnet .

Lose Kopplung gibt Ihnen mehr Flexibilität. Anstatt jede Seite eng mit jeder anderen Seite zu verbinden, sind sie alle eng mit einem einzigen Objekt verbunden: dem Controller. Solange jede Seite nur den Controller kennt, kann jede Seite jederzeit geändert werden, ohne den Rest des Programms zu beeinflussen.

Natürlich, wenn Sie den Controller ändern, müssen Sie alle Seiten ändern, aber wenn Sie einen guten Job machen, den Controller zu entcasting, der weniger wahrscheinlich ist und leichter zu verwalten, wenn es auftritt.

Das hat mit dem globalen Rahmen zu tun.

Wenn Sie eine Variable innerhalb einer class erstellen, wird sie nur innerhalb dieser function existieren. Wenn Sie eine Variable innerhalb einer class (oder function) in den globalen Rahmen “übertragen” wollen, verwenden Sie global .

 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 

Um den Speicher zu visualisieren, können Sie pythontutor verwenden , da es Ihnen Schritt für Schritt zeigt, wie der Speicher erstellt wird.

Ich hoffe, ich konnte dir helfen!

BEARBEITEN

Ich denke, ich sollte hinzufügen, dass wenn Sie eine Variable innerhalb einer class / function mit dem gleichen Namen wie eine Variable im globalen Rahmen definieren, wird es nicht die globale Variable entfernen. Stattdessen wird ein neuer (mit dem gleichen Namen) in einem eigenen Rahmen erstellt. Eine class oder function verwendet die Variable immer in einem eigenen Rahmen, sofern verfügbar.

 x = 5 def print_variable(): x = 3 print(x) print(x) print_variable() # OUTPUT: # 5 # 3