2016-05-27 4 views
-1

Ich versuche, zwei Eingabefelder und eine 'OK' Taste, die beide Einträge verarbeitet: Ich verstehe nicht die init() -Funktion oder der Grund 'selbst' muss dabei einbezogen werden. Ich möchte auf die Einträge außerhalb dieser Klasse und Hauptschleife zugreifen. Die Einträge sollten String-Typ sein.mehrere Einträge Widgets und ein Button Widget in tkinter

from tkinter import * 
root = Tk() 
root.geometry("550x145+500+300") 

class myDose: 
    def __init__(self): 

     l1 = Label(text="Enter the prescription dose to three (3) decimal places [cGy]").pack() 
     e1 = Entry(root) 
     e1.pack() 

     l2 = Label(text="Save new excel file as...").pack() 
     e2 = Entry(root) 
     e2.pack() 

     l3 = Label(text="click 'OK', and then close window.").pack() 

     b = Button(root, text="OK", command=submit) 
     b.pack() 

    def submit(self): 
     print(e1.get()) 
     print(e2.get()) 

D = myDose() 
root.mainloop() 

#I want to access the entries, e1 and e2, outside the mainloop 
print(D.e1) 
print(D.e2) 
+0

Mit "außerhalb der Hauptschleife" bedeutet das "nachdem das Fenster zerstört wurde". Ist dir das bewusst? Oder fragen Sie, wie Code nach "Hauptschleife" ausgeführt wird, aber das Fenster immer noch sichtbar ist? –

+0

Ich habe Funktionen oberhalb dieser Klasse geschrieben. Sie hängen von dieser e1-Variablen ab. Deshalb möchte ich die Benutzereintragsnummer 1 erhalten. Unter dieser Klasse habe ich in meinem Programm Code, der wie eine main() -Funktion ist (d. H., Wo mein Code beginnt zu laufen) und das hängt von e2 ab. – Michael

+0

Sind sie abhängig von dem e1 _widget_ oder dem Wert, der in das Widget eingegeben wurde? –

Antwort

1

Das Problem ist, dass mainloop nicht beendet wird, bis das Stammfenster zerstört wird. Sobald das Root-Fenster zerstört ist, können Sie nicht mehr auf die Widgets im Root-Fenster zugreifen. Sie können jedoch auf Nicht-Widget-Attribute des Objekts zugreifen.

Wenn das ist, was Sie wollen - um das Fenster zu zerstören und Zugriff auf die Werte im Widget - müssen Sie die Werte vor dem Zerstören des Fensters speichern.

Zum Beispiel in Ihrem einreichen Sie die Werte wie folgt retten könnte:

def submit(self): 
    self.data = {"e1": self.e1.get(), "e2": self.e2.get()} 

Sobald das Fenster zerstört wird, haben Sie noch einen Verweis auf das Anwendungsobjekt, so dass Sie immer noch die nicht-Widget zugreifen können Attribute der Klasse:

... 
D = myDose(root) 
root.mainloop() 

print D.data["e1"] 
print D.data["e2"] 

auf die ursprüngliche Frage auf Kommentare Basierend, erwähnen Sie, dass in Ihrem Code später müssen Sie askopenfilename verwenden. Wenn dies der Fall ist, sollten Sie die Notwendigkeit, Code nach mainloop auszuführen, überdenken. Tkinter ist so konzipiert, dass ein Root-Fenster genau einmal erstellt wird und das Programm sofort beendet wird, nachdem mainloop beendet wurde.

Sie können Programme schreiben, wie Sie wollen, aber ich denke, dass Ihr Code auf lange Sicht leichter zu pflegen und zu modifizieren ist, wenn Sie sich an normale Entwurfsmuster halten. Verschieben Sie Ihren "echten" Code in eine Methode der App-Klasse und das eliminiert alle Probleme, die mit Widgets verbunden sind, die zerstört werden.

+0

das ist ausgezeichnet. Sie wissen, was ich meine – Michael

+0

@Michael - Bitte beachten Sie, dass das Wissen, was Sie meinen, nicht gleichbedeutend damit ist, zuzustimmen, dass Sie Ihr Programm in einer vernünftigen Weise konstruieren. Ich empfehle, Tkinter-Anwendungen zu untersuchen, insbesondere, wie man mit solchen Anwendungen auf ein Datenmodell zugreifen kann, damit Sie Ihr Programm korrekt schreiben können. Dadurch wird es viel einfacher, später mit Ihrem Code zu arbeiten. – TigerhawkT3

+0

@ TigerhawkT3 aber es funktioniert so, wie ich es will ... – Michael

0

Ihr Ansatz ist grundlegend fehlerhaft. mainloop() macht was es sagt: startet eine Schleife. Die darauffolgenden Zeilen werden erst ausgeführt, wenn diese Schleife beendet ist. Dies bedeutet, dass Ihre Anwendung geschlossen wurde. Da Sie bereits eine Klasse mit Tkinter Sachen drin haben, beenden Sie einfach den Übergang zu einem OO-Ansatz:

from tkinter import * 

class myDose: 
    def __init__(self, root): 
     root.geometry("550x145+500+300") 

     self.l1 = Label(root, text="Enter the prescription dose to three (3) decimal places [cGy]") 
     self.l1.pack() 
     self.e1 = Entry(root) 
     self.e1.pack() 

     self.l2 = Label(root, text="Save new excel file as...") 
     self.l2.pack() 
     self.e2 = Entry(root) 
     self.e2.pack() 

     self.l3 = Label(root, text="click 'OK', and then close window.") 
     self.l3.pack() 

     self.b = Button(root, text="OK", command=self.submit) 
     self.b.pack() 

    def submit(self): 
     print(self.e1.get()) 
     print(self.e2.get()) 

root = Tk() 
D = myDose(root) 
root.mainloop() 

ich empfehlen, sich gründlicher darüber, wie grundlegende Konzepte wie Objekte und Klassen arbeiten, bevor eine vollständige GUI-Anwendung.

+0

Was meinen Sie mit einem OO-Ansatz? Ich muss auf diese Einträge unter der Zeile "root.mainloop" zugreifen mein anderer Code hängt davon ab, diese Werte @ TigerhawkT3 – Michael

+0

gehen Drucken (D.E1) unter root.mainloop gibt mir einige zufällige Wert wie .6745325 – Michael

+0

@Michael Haben Sie es versucht macht 'print (D.e1.get())' nach 'root.mainloop()' in TigerhawkT3s Version deines Skripts? –

0

Hier ist eine schnelle Lösung.

Das Problem mit Ihrer Version und der modifizierten Version von TigerhawkT3 ist, dass die Entry Widgets nicht mehr gültig sind, wenn Sie das Fenster schließen, also müssen Sie die Daten speichern, bevor Sie das Fenster schließen. Eine Möglichkeit besteht darin, Tkinter StringVar s an die Entry Widgets anzuhängen. Die Werte in StringVar sind nach dem Schließen des Fensters verfügbar.

import tkinter as tk 

class myDose: 
    def __init__(self, root): 
     root.geometry("550x145+500+300") 

     l = tk.Label(root, text="Enter the prescription dose to three (3) decimal places [cGy]") 
     l.pack() 
     self.dosage = tk.StringVar() 
     e = tk.Entry(root, textvariable=self.dosage) 
     e.pack() 

     l = tk.Label(root, text="Save new excel file as...") 
     l.pack() 
     self.savename = tk.StringVar() 
     e = tk.Entry(root, textvariable=self.savename) 
     e.pack() 

     l = tk.Label(root, text="Enter the data and then close window.") 
     l.pack() 

     root.mainloop() 

D = myDose(tk.Tk()) 

print(D.dosage.get()) 
print(D.savename.get()) 

Beachten Sie, dass ich die import Anweisung geändert habe. Es ist viel sauberer nicht

from tkinter import * 

tun wie die clutters Ihren Namensraum mit über 100 Namen, um potenzielle Namenskollisionen führen.


__init__() Die Funktion ist ein Verfahren der myDose Klasse. Die Klasse __init__() einer Klasse wird aufgerufen, wenn eine Instanz dieser Klasse erstellt wird. In Ihrem Code geschieht, wenn Sie

D = myDose() 

In meiner Version zu tun ist es, wenn diese Zeile ausgeführt wird:

D = myDose(tk.Tk()) 

, die zuerst die Tkinter Root-Fenster erzeugt, die dann auf myDose übergeben wird; Dieses Root-Fenster ist dann für mein __init__() als sein root Argument verfügbar.

Der Name self wird innerhalb der Klasse verwendet, um auf die aktuelle Klasseninstanz zu verweisen. Außerhalb der Klasse müssen wir den tatsächlichen Namen verwenden, dem die Instanz zugewiesen wurde, in diesem Fall .

+0

Wenn Sie "das Problem mit der früheren Version" sagen, über welche "frühere Version" sprechen Sie? Antworten können in einer anderen Reihenfolge sein als beim Schreiben Ihrer Antwort. Beziehen Sie sich auf die Version in der Frage oder in einer der anderen Antworten? Können Sie in Ihrer Antwort genauer sein? –