Seite 1 von 1

Problem mit mehreren Fenstern

Verfasst: Mittwoch 19. Dezember 2018, 18:55
von holgie
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]

Re: Problem mit mehreren Fenstern

Verfasst: Mittwoch 19. Dezember 2018, 19:08
von Sirius3
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.

Re: Problem mit mehreren Fenstern

Verfasst: Mittwoch 19. Dezember 2018, 19:30
von holgie
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ß

Re: Problem mit mehreren Fenstern

Verfasst: Mittwoch 19. Dezember 2018, 19:45
von Sirius3
Da hast Du aber nur die Referenz auf das zweite TopLevel-Fenster, und nicht auf die Instanz von hauptfenster.

Re: Problem mit mehreren Fenstern

Verfasst: Sonntag 23. Dezember 2018, 22:35
von holgie
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()

Re: Problem mit mehreren Fenstern

Verfasst: Montag 24. Dezember 2018, 00:03
von __blackjack__
@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.

Re: Problem mit mehreren Fenstern

Verfasst: Montag 24. Dezember 2018, 00:04
von Sirius3
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`.

Re: Problem mit mehreren Fenstern

Verfasst: Dienstag 25. Dezember 2018, 22:21
von holgie
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

Re: Problem mit mehreren Fenstern

Verfasst: Dienstag 25. Dezember 2018, 22:45
von __blackjack__
@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.

Re: Problem mit mehreren Fenstern

Verfasst: Dienstag 25. Dezember 2018, 23:17
von holgie
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

Re: Problem mit mehreren Fenstern

Verfasst: Dienstag 25. Dezember 2018, 23:52
von Sirius3
An welche Variable ist denn die Instanz, die später an `haupt` gebunden ist, in `__init__` gebunden?