Problem mit mehreren Fenstern

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
holgie
User
Beiträge: 12
Registriert: Sonntag 18. Januar 2015, 16:55

Hallo zusammen,
ich habe ein Problem bei der Programmierung von mehreren Fenstern und habe daher einmal ein Beispielprogramm geschrieben. Darin möchte ich über Buttons nacheinander 3 Fenster öffnen und schließlich im dritten Fenster eine Auswahl treffen die ich dann im ersten Fenster weiterverarbeite.
Dabei habe ich folgende Probleme:
1) wenn ich das Programm durchlaufen lasse und im dritten Fenster die Auswahl treffe wird immer ein neues erstes Fenster erzeugt. Das möchte ich aber nicht. Es soll das gleiche, erste Fenster erhalten und modifiziert werden. Die Zeile haupt = hauptfenster.wertuebernehmen(hauptfenster(Tk()), self.a) wird wohl falsch sein. Ich weiß aber nicht wie ich es ändern muss.
2) Ich habe in dem Programm mal zwei "Möglichkeiten" auskommentiert wie man meiner Meinung nach die alten Fenster schließen können müsste.
Wenn ich das self.master2.destroy() in class zweites() ausführen lasse, wird das zweite Fenster wie gewünscht gelöscht, allerdings wird das dritte auch nicht mehr geladen. Wenn ich versuche in der class drittes() das zweite Fenster über zweites.master2.destroy() zu schließen bekomme ich die Fehlermeldung AttributeError: type object 'zweites' has no attribute 'master2'
Irgendwie fehlt noch das Grundverständniss. Ich komme leider nicht so oft zum Programmieren. Hoffe daher das ihr mir weiterhelfen könnt mit Erklärungen und evtl. auch links oder Buchempfehlungen.
Danke im Vorraus!!!!
Gruß
Holger

Code: Alles auswählen

from tkinter import *

class hauptfenster():
           
    def __init__(self,master):
        self.master= master
        self.master.geometry("1300x500+40+40")
        self.master.title("Hauptfenster")
        self.fra1= Frame(self.master)
        self.fra1.pack()
        self.button1= Button(self.fra1,text= "zweites Fenster", command=self.ladezweites)
        self.button1.pack()
        self.label1=Label(self.fra1,text="Hallo")
        self.label1.pack()
        
    def ladezweites(self):
    
        root2= Toplevel(self.master)
        myGui=zweites(root2)
        
    
    def wertuebernehmen(self,rech2):
        print(rech2)
        self.rechnen(rech2)
    
    def rechnen(self,rech2):
        
        self.label1["text"]=rech2
             
class zweites():
    
    def __init__(self,master):
        self.master2 = master
        self.master2.geometry("200x200+20+20")
        self.master2.title("Zweites Fenster")
        #ima = PhotoImage(file='test.gif')
        self.label = Label(self.master2)
        self.label.pack()
        self.button1= Button(self.master2,text= "drittes Fenster", command=self.ladedrittes)
        self.button1.pack()
        
    def ladedrittes(self):
        root3=Toplevel(self.master2)
        myGui=drittes(root3)
        #self.master2.destroy()
class drittes():
    
        
    def __init__(self,master):
            
        self.master3 = master
        self.master3.geometry("200x200+20+20")
        self.master3.title("drittes")
        self.rech= StringVar()
        self.fenster = Frame(self.master3)
        self.fenster.pack()
        self.radio1=Radiobutton(self.fenster, text="1", variable =self.rech, value = "1")
        self.radio1.pack()
        self.radio2=Radiobutton(self.fenster, text="2", variable =self.rech, value = "2")
        self.radio2.pack()
        self.radio1.select()
        self.button1= Button(self.fenster,text= " auslesen", command=(self.auslesen))
        self.button1.pack()  
        self.rech2=""
        #zweites.master2.destroy
    def auslesen(self):
        self.a=self.rech.get()
        haupt = hauptfenster.wertuebernehmen(hauptfenster(Tk()), self.a)    
         
root = Tk()
hauptfenster(root)
root.mainloop()  
[code]
Sirius3
User
Beiträge: 18268
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn Du kein neues erstes Fenster haben willst, dann mach einfach keins. Du mußt eben über zweites die Referenz des ersten an das Dritte übergeben.

Ersetze `from tkinter import *` durch `import tk` und referenziere alles aus tkinter über tk.xxx.
Klassennamen werden mit großem Anfangsbuchstaben geschrieben. Das zuweisen von self.rech.get() an self.a unnötig. Die letzten drei Zeilen sollten in einer Funktion Namens main stehen, die man zum Schluß einfach über

Code: Alles auswählen

if __name__ == '__main__':
    main()
aufruft.
holgie
User
Beiträge: 12
Registriert: Sonntag 18. Januar 2015, 16:55

Hallo,
sorry, kannst du etwas genauer erklären wie ich die Referenz übergeben muss. Ich dachte ich hätte das mit self. masterx=master gemacht??
Gruß
Sirius3
User
Beiträge: 18268
Registriert: Sonntag 21. Oktober 2012, 17:20

Da hast Du aber nur die Referenz auf das zweite TopLevel-Fenster, und nicht auf die Instanz von hauptfenster.
holgie
User
Beiträge: 12
Registriert: Sonntag 18. Januar 2015, 16:55

Hallo,
die Instanz habe ich nun übergeben. Damit kann ich nun auf das Grundfenster zugreifen ohne es neu zu erzeugen. Danke für die Hilfe!!!
Ich habe auch mal die Funktion und die if __name__ == '__main__': eingefügt. Ist das so richtig? Der Sinn ist also das es als eigenständiges Programm kompiliert wird aber nicht wenn es importiert wird richtig?
Leider habe ich immer noch Probleme die Fenster zu schließen. Warum bekomme ich bei Zweites.master2.destroy() eine Fehlermeldung Zweites has no attribute master2. Das habe ich doch in der Konstrukturmethode zugewiesen? Und das self.master2.destroy() müsste doch auch eigentlich funktionieren?
Danke vorab.
Gruß
Holger

Code: Alles auswählen

from tkinter import *

class Hauptfenster():
           
    def __init__(self,master):   #Konstruktormethode
        self.master= master
        self.master.geometry("1300x500+40+40")
        self.master.title("Hauptfenster")
        self.fra1= Frame(self.master)
        self.fra1.pack()
        self.button1= Button(self.fra1,text= "zweites Fenster", command=self.ladezweites)
        self.button1.pack()
        self.label1=Label(self.fra1,text="Hallo")
        self.label1.pack()
       
       
    def ladezweites(self):
        
        root2= Toplevel(self.master)
        myGui=Zweites(root2, haupt)
        
    
    def wertuebernehmen(self,rech2):
        print(rech2)
        self.rechnen(rech2)
    
    def rechnen(self,rech2):
        
        self.label1["text"]=rech2
             
class Zweites():
    
    def __init__(self,master, haupt):
        self.master2 = master
        self.haupt = haupt
        self.master2.geometry("200x200+20+20")
        self.master2.title("Zweites Fenster")
        #ima = PhotoImage(file='test.gif')
        self.label = Label(self.master2)
        self.label.pack()
        self.button1= Button(self.master2,text= "drittes Fenster", command=self.ladedrittes)
        self.button1.pack()
        
        
    def ladedrittes(self):
        root3=Toplevel(self.master2)
        myGui=Drittes(root3, haupt)
        #self.master2.destroy()
        
class Drittes():
    
        
    def __init__(self,master, haupt):
            
        self.master3 = master
        self.haupt = haupt
        self.master3.geometry("200x200+20+20")
        self.master3.title("drittes")
        self.rech= StringVar()
        self.fenster = Frame(self.master3)
        self.fenster.pack()
        self.radio1=Radiobutton(self.fenster, text="1", variable =self.rech, value = "1")
        self.radio1.pack()
        self.radio2=Radiobutton(self.fenster, text="2", variable =self.rech, value = "2")
        self.radio2.pack()
        self.radio1.select()
        self.button1= Button(self.fenster,text= " auslesen", command=(self.auslesen))
        self.button1.pack()  
        self.rech2=""
        #Zweites.master2.destroy()
        
    def auslesen(self):
        self.a=self.rech.get()
        haupt.wertuebernehmen(self.a) 


def  main():
    global haupt
    root = Tk()
    haupt = Hauptfenster(root)
    root.mainloop() 
    

if __name__ == '__main__':
    main()
Benutzeravatar
__blackjack__
User
Beiträge: 14036
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@holgie: Das ``global haupt`` in der `main()` gehört da nicht hin. Es ist ja gerade der Sinn den Code in eine Funktion zu stecken, damit man eben *keine* modulglobalen Variablen hat, die alles undurchsichtig, und fehleranfällig machen.

Ich finde die Aufteilung im Code schräg. Eine Klasse die Hauptfenster heisst, aber gar kein Fenster ist, aber die Eigenschaften eines übergeben Fensters ändern. Das heisst in der Klasse `master`, Du änderst also aus einem Objekt das tiefer in der Hierarchie liegt Eigenschaften von einem Objekt das höher in der Hierarchie liegt. In die Richtung sollte man aber nicht gehen. Das Muster zieht sich auch durch die anderen Klassen.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Sirius3
User
Beiträge: 18268
Registriert: Sonntag 21. Oktober 2012, 17:20

Irgendwie habe ich glaube ich schon was von *-Importen geschrieben. Die Nummern an den Variablennamen sind unsinnig, da sie keine Information enthalten und wild gewürfelt erscheinen. Bei `haupt` fehlt jeweils das `self` weshalb Du verbotenerweise `global` benutzt hast. Dagegen sind die meisten anderen Attribute besser einfache lokale Variablen, weil sie sonst nicht weiter benutzt werden, besonders `a`.
holgie
User
Beiträge: 12
Registriert: Sonntag 18. Januar 2015, 16:55

Hallo,
irgendwie stehe ich jetzt komplett auf dem Schlauch.
Ich habe keine Ahnung wie ich das global wegbekommen soll. Kann man mir evtl. ein paar zus. Infos geben?
Außerdem verstehe ich diese Aussage nicht:
Eine Klasse die Hauptfenster heisst, aber gar kein Fenster ist, aber die Eigenschaften eines übergeben Fensters ändern. Das heisst in der Klasse `master`, Du änderst also aus einem Objekt das tiefer in der Hierarchie liegt Eigenschaften von einem Objekt das höher in der Hierarchie liegt. In die Richtung sollte man aber nicht gehen.
In der Klasse Hauptfenster erstelle ich doch das Hauptfenster.Von hier aus übergebe ich dann die Instanz des Hauptfensters in die anderen Fensterklassen damit ich von dem zuletzt erstellten Fenster aus das Hauptfenster ändern kann.
Was konkret habe ich da falsch gemacht?
Sorry für die schlechte Benennung der Variablen. Ich habe nur ein kleines Programm geschrieben um mein Problem besser darstellen zu können.
Gruß
Holger
Benutzeravatar
__blackjack__
User
Beiträge: 14036
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@holgie: Einfach die Zeile mit dem ``global`` löschen und dann nicht mehr auf magische Weise auf das globale `haupt` zugreifen wollen. Ich denke Du reichst das bereits durch und hast das an ein Attribut gebunden. Falls nicht – genau das machen.

Bei dem was Du nicht verstehst müsstest Du schon sagen *was* Du nicht verstehst. `Hauptfenster` ist kein Hauptfenster. `Tk` ist ein Hauptfenster. `Hauptfenster` ist gar kein GUI-Objekt. Das wäre ein Hauptfenster wenn es von `Tk` erben würde. Wenn Hauptfenster ein GUI-Objekt wäre, und das übergebene *tatsächliche* Hauptfenster-Objekt an ein Attribut mit dem Namen `master` gebunden wird, dann würde man in `Hauptfenster` dem *Meister* nicht sagen wie sein Titel und seine Grösse zu sein hat. Das steht dem untergeordneten Objekt nicht zu. Diese Eigenschaften würde man ausserhalb von `Hauptfenster.__init__()` setzen *bevor* man das `Tk`-Objekt an diese Methode übergibt. Oder man würde das in der `__init__()` erst erzeugen, und es nicht an einen Namen wie `master` binden, denn das wäre es dann nicht.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
holgie
User
Beiträge: 12
Registriert: Sonntag 18. Januar 2015, 16:55

Hallo nochmal,
wenn ich das richtig verstehe muss ich ja, um das Global zu ersetzen, das haupt in der Konstruktormethode mit self.haupt = haupt übergeben:

def __init__(self,master,haupt ): #Konstruktormethode
self.master= master
self.haupt=haupt

Damit funktioniert aber das haupt = Hauptfenster(root) nicht mehr weil ein Argument zu wenig übertragen wird.

haupt = Hauptfenster(root, haupt) funktioniert natürlich auch nicht.

Danke!
Holger
Sirius3
User
Beiträge: 18268
Registriert: Sonntag 21. Oktober 2012, 17:20

An welche Variable ist denn die Instanz, die später an `haupt` gebunden ist, in `__init__` gebunden?
Antworten