Klassen. Attribute, Methoden für eine tkinter GUI? Wozu?

Fragen zu Tkinter.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Es wird immer wieder geschrieben, man solle Klassen. Attribute und Methoden für eine tkinter GUI verwenden. Aber warum, denn das, wozu auch?

Was man braucht, ist doch nur eine einzige Variable. Man muß in tkinter den Master übergeben. Daher braucht man eine Variable für den Master. Gut, manchmal läßt sich auch eine Funktion nicht vermeiden, da lambda nur für einzeilig ausreicht. Da muß man dann eben auch einen Namen für eine Funktion definieren, die man einmalig aufruft und dann wieder vergessen kann. Oder in diesem Fall war es dann ein Dictionary.

Hier etwa hat man 138 Zeilen Code, wobei Vieles nur Klassendefinitionen mit Zwischenraum sind und das Widget und dessen Layout sind dann doppelt. Und das sind Klassen und Attribute, die man gar nicht braucht:

viewtopic.php?f=18&t=41121&p=314101#p314063

Es geht doch ohne solche Klassen auch viel kürzer:

Code: Alles auswählen

import tkinter as tk

from functools import partial
 
# so etwas würde man importieren =================
class EventBroker():
    def __init__(self):
        self._dictionary_ = {}
 
    def subscribe(self,message_id,callback):
        self._dictionary_[message_id] = callback
 
    def publish(self,message_id,*args,**kwargs):
        self._dictionary_[message_id](*args,**kwargs)
 
eventbroker = EventBroker()
publish = eventbroker.publish
subscribe = eventbroker.subscribe
# ==============================================

def main():
    master = tk.Tk()
    master = tk.Frame(master)
    master.pack(fill='both', expand=1)
    master.rowconfigure(0,weight=1)
    master.columnconfigure(0,weight=1)
    frames = {}
    subscribe('SHOW_FRAME',lambda frame_id, frames=frames: frames[frame_id].lift())
    master = tk.Frame(master)
    frames['Benutzereinstellungen'] = master
    master.grid(sticky='nesw', row=0)
    tk.Label(master,font = 'Verdana 12', text='Page One!!!').pack(padx=10, pady=20)
    tk.Button(master,text = 'Back to Home',command=partial(publish,'SHOW_FRAME','RemoteManager')).pack()
    tk.Button(master,text = 'Page Two',command=partial(publish,'SHOW_FRAME','PageTwo')).pack()
    master = tk.Frame(master.master)
    frames['PageTwo'] = master
    master.grid(sticky='nesw', row=0)
    tk.Label(master,font = 'Verdana 12', text='Page Two!!!').pack(padx=10, pady=10)
    tk.Button(master,text = 'Back to Home',command=partial(publish,'SHOW_FRAME','RemoteManager')).pack()
    tk.Button(master,text = 'Page One',command=partial(publish,'SHOW_FRAME','Benutzereinstellungen')).pack()
    master = tk.Frame(master.master)
    frames['RemoteManager'] = master
    master.grid(sticky='nesw', row=0)
    tk.Label(master,text = 'Willkommen im Remote Manager').pack(padx=25, pady=15)
    tk.Button(master,text = 'Benutzereinstellungen', width = 18,command=partial(publish,'SHOW_FRAME','Benutzereinstellungen')).pack()
    tk.Label(master).pack(padx=25, pady=1)
    tk.Button(master,text ='Bildschirmeinstellungen', width = 18).pack()
    tk.Label(master).pack(padx=25, pady=1)
    tk.Button(master,text = 'Servereinstellungen', width = 18,command=partial(publish,'SHOW_FRAME','PageTwo')).pack()
    tk.Label(master).pack(padx=25, pady=1)
    frames['RemoteManager'].lift()
    frames = None # Globaler Zugriff, nein danke
    master = tk.Menu(master.master.master)
    master.master['menu'] = master
    master = tk.Menu(master,tearoff=0)
    master.add_command(label='Komplettes Setup',command=partial(publish,'SHOW_FRAME','RemoteManager'))
    master.add_separator()
    master.add_command(label='Benutzereinstellungen',command=partial(publish,'SHOW_FRAME','Benutzereinstellungen'))
    master.add_command(label='Bildschirmeinstellungen')
    master.add_command(label='Servereinstellungen',command=partial(publish,'SHOW_FRAME','PageTwo'))
    master.add_separator()
    master.add_command(label ='Beenden')
    master.master.add_cascade(label='Manager',menu=master)
    master = tk.Menu(master.master,tearoff=0)
    master.add_command(label='Info')
    master.master.add_cascade(label='Hilfe',menu=master)
    master = master.master.master
    master.mainloop()

if __name__ == '__main__':
    main()
Dieser Code macht genau dasselbe und ist wesentlich kürzer ohne diesen ganzen Firlefanz mit den Klassen. Na gut, das mit dem vielen master ist ein wenig blöd, aber was muss tkinter auch so etwas unbedingt wollen.
BlackJack

@Alfons Mittelmeyer: Das ist ehr unübersichthlich die ganze GUI in eine Funktion zu schreiben, zudem ist die ja noch nicht einmal vollständig, denn in die `Frame`\s kommt ja noch Inhalt. Und wenn da dann noch Zustand dazu kommt, dann kommst Du nicht mehr ohne Klassen aus, beziehungsweise wird eine Lösung ohne Klassen dann noch unübersichtlicher als das jetzt eh schon ist.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Schön zu erkennen ist hier die Programmlogik. Die ist in Zeile 28.
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: schön, Du hast globale Variablen vermieden, indem Du nur *eine* Funktion hast. Glückwunsch.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

BlackJack hat geschrieben:@Alfons Mittelmeyer: Das ist ehr unübersichthlich die ganze GUI in eine Funktion zu schreiben, zudem ist die ja noch nicht einmal vollständig, denn in die `Frame`\s kommt ja noch Inhalt.
Natürlich ist die Lösung vollständig. Denn der Inhalt ist ja da: Zeilen 30, 36 und 42
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben:@Alfons Mittelmeyer: schön, Du hast globale Variablen vermieden, indem Du nur *eine* Funktion hast. Glückwunsch.
Das war es ja nicht nur. Indem ich auch nur eine Variable habe, nämlich master. Die war nicht zu vermeiden und frames hatte ich auch gebraucht, aber danach gleich wieder gelöscht.

Naja, hätte ich master nicht gebraucht und frames auch nicht, hätte ich nicht einmal eine Funktion gebraucht, um globale Variablen zu vermeiden. Denn wenn man keine Variablen hat, kann auch keine global sein.

Es ist eben nun einmal so: ohne irgendein Widget hat man auch keinen Zugriff auf tkinter.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

BlackJack hat geschrieben:@Alfons Mittelmeyer: Das ist ehr unübersichthlich die ganze GUI in eine Funktion zu schreiben
Unübersichtlich ist sie halt, wenn man nicht einrückt, weil man da die Ebenen nicht sieht. Aber so wird es dann schon übersichtlich, nicht wahr?

Code: Alles auswählen

import tkinter as tk

from functools import partial
 
# so etwas würde man importieren =================
class EventBroker():
    def __init__(self):
        self._dictionary_ = {}
 
    def subscribe(self,message_id,callback):
        self._dictionary_[message_id] = callback
 
    def publish(self,message_id,*args,**kwargs):
        self._dictionary_[message_id](*args,**kwargs)
 
eventbroker = EventBroker()
publish = eventbroker.publish
subscribe = eventbroker.subscribe
# ==============================================

def main():
    master = tk.Tk()
    master = tk.Frame(master)
    master.pack(fill='both', expand=1)
    if True:
        master.rowconfigure(0,weight=1)
        master.columnconfigure(0,weight=1)
        frames = {}
        subscribe('SHOW_FRAME',lambda frame_id, frames=frames: frames[frame_id].lift())
        master = tk.Frame(master)
        master.grid(sticky='nesw', row=0)
        frames['Benutzereinstellungen'] = master
        if True:
            tk.Label(master,font = 'Verdana 12', text='Page One!!!').pack(padx=10, pady=20)
            tk.Button(master,text = 'Back to Home',command=partial(publish,'SHOW_FRAME','RemoteManager')).pack()
            tk.Button(master,text = 'Page Two',command=partial(publish,'SHOW_FRAME','PageTwo')).pack()
        master = master.master
        master = tk.Frame(master)
        master.grid(sticky='nesw', row=0)
        frames['PageTwo'] = master
        if True:    
            tk.Label(master,font = 'Verdana 12', text='Page Two!!!').pack(padx=10, pady=10)
            tk.Button(master,text = 'Back to Home',command=partial(publish,'SHOW_FRAME','RemoteManager')).pack()
            tk.Button(master,text = 'Page One',command=partial(publish,'SHOW_FRAME','Benutzereinstellungen')).pack()
        master = master.master
        master = tk.Frame(master)
        master.grid(sticky='nesw', row=0)
        frames['RemoteManager'] = master
        if True:
            tk.Label(master,text = 'Willkommen im Remote Manager').pack(padx=25, pady=15)
            tk.Button(master,text = 'Benutzereinstellungen', width = 18,command=partial(publish,'SHOW_FRAME','Benutzereinstellungen')).pack()
            tk.Label(master).pack(padx=25, pady=1)
            tk.Button(master,text ='Bildschirmeinstellungen', width = 18).pack()
            tk.Label(master).pack(padx=25, pady=1)
            tk.Button(master,text = 'Servereinstellungen', width = 18,command=partial(publish,'SHOW_FRAME','PageTwo')).pack()
            tk.Label(master).pack(padx=25, pady=1)
        master = master.master
        frames['RemoteManager'].lift()
        frames = None # Globales Zugriff, nein danke
    master = master.master
    master = tk.Menu(master)
    master.master['menu'] = master
    if True:
        master = tk.Menu(master,tearoff=0)
        if True:
            master.add_command(label='Komplettes Setup',command=partial(publish,'SHOW_FRAME','RemoteManager'))
            master.add_separator()
            master.add_command(label='Benutzereinstellungen',command=partial(publish,'SHOW_FRAME','Benutzereinstellungen'))
            master.add_command(label='Bildschirmeinstellungen')
            master.add_command(label='Servereinstellungen',command=partial(publish,'SHOW_FRAME','PageTwo'))
            master.add_separator()
            master.add_command(label ='Beenden')
        master.master.add_cascade(label='Manager',menu=master)
        master = master.master
        master = tk.Menu(master,tearoff=0)
        if True:
            master.add_command(label='Info')
        master.master.add_cascade(label='Hilfe',menu=master)
        master = master.master
    master = master.master
    master.mainloop()

if __name__ == '__main__':
    main()
Die 'Bildschirmeinstellungen' sind allerdings noch nicht implementiert. Aber da kann ich nichts dafür.

Vielleicht sollte man statt nur if True:
das schreiben:

Code: Alles auswählen

if True: # children
Dann weiß man doch genau, was das ist, oder?
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Irgendetwas stimmt noch nicht mit den Einrückungen. Zeile 23 hätte ich ja auch schon einrücken müssen. Aber es stimmt schon so, weil ich erst immer nachher einrücke.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Naja, rückt man eben zweimal ein: Wenn der master wechselt und dann nochmals, wenn man zum neuen Master noch children erfasst, auch wenn dabei der Master nicht mehr wechselt. Das ist vielleicht deutlicher:

Code: Alles auswählen

import tkinter as tk
 
from functools import partial
 
# so etwas würde man importieren =================
class EventBroker():
    def __init__(self):
        self._dictionary_ = {}
 
    def subscribe(self,message_id,callback):
        self._dictionary_[message_id] = callback
 
    def publish(self,message_id,*args,**kwargs):
        self._dictionary_[message_id](*args,**kwargs)
 
eventbroker = EventBroker()
publish = eventbroker.publish
subscribe = eventbroker.subscribe
# ==============================================
 
def main():
    master = tk.Tk()
    if True: # children
        master = tk.Frame(master)
        master.pack(fill='both', expand=1)
        master.rowconfigure(0,weight=1)
        master.columnconfigure(0,weight=1)
        frames = {}
        subscribe('SHOW_FRAME',lambda frame_id, frames=frames: frames[frame_id].lift())
        if True: # children
            master = tk.Frame(master)
            master.grid(sticky='nesw', row=0)
            frames['Benutzereinstellungen'] = master
            if True: # children
                tk.Label(master,font = 'Verdana 12', text='Page One!!!').pack(padx=10, pady=20)
                tk.Button(master,text = 'Back to Home',command=partial(publish,'SHOW_FRAME','RemoteManager')).pack()
                tk.Button(master,text = 'Page Two',command=partial(publish,'SHOW_FRAME','PageTwo')).pack()
        master = master.master
        if True: # children
            master = tk.Frame(master)
            master.grid(sticky='nesw', row=0)
            frames['PageTwo'] = master
            if True: # children
                tk.Label(master,font = 'Verdana 12', text='Page Two!!!').pack(padx=10, pady=10)
                tk.Button(master,text = 'Back to Home',command=partial(publish,'SHOW_FRAME','RemoteManager')).pack()
                tk.Button(master,text = 'Page One',command=partial(publish,'SHOW_FRAME','Benutzereinstellungen')).pack()
        master = master.master
        if True: # children
            master = tk.Frame(master)
            master.grid(sticky='nesw', row=0)
            frames['RemoteManager'] = master
            if True: # children
                tk.Label(master,text = 'Willkommen im Remote Manager').pack(padx=25, pady=15)
                tk.Button(master,text = 'Benutzereinstellungen', width = 18,command=partial(publish,'SHOW_FRAME','Benutzereinstellungen')).pack()
                tk.Label(master).pack(padx=25, pady=1)
                tk.Button(master,text ='Bildschirmeinstellungen', width = 18).pack()
                tk.Label(master).pack(padx=25, pady=1)
                tk.Button(master,text = 'Servereinstellungen', width = 18,command=partial(publish,'SHOW_FRAME','PageTwo')).pack()
                tk.Label(master).pack(padx=25, pady=1)
        master = master.master
        frames['RemoteManager'].lift()
        frames = None # Globales Zugriff, nein danke
    master = master.master
    if True: # children
        master = tk.Menu(master)
        master.master['menu'] = master
        if True: # children
            master = tk.Menu(master,tearoff=0)
            if True:  # children
                master.add_command(label='Komplettes Setup',command=partial(publish,'SHOW_FRAME','RemoteManager'))
                master.add_separator()
                master.add_command(label='Benutzereinstellungen',command=partial(publish,'SHOW_FRAME','Benutzereinstellungen'))
                master.add_command(label='Bildschirmeinstellungen')
                master.add_command(label='Servereinstellungen',command=partial(publish,'SHOW_FRAME','PageTwo'))
                master.add_separator()
                master.add_command(label ='Beenden')
        master.master.add_cascade(label='Manager',menu=master)
        master = master.master
        if True: # children
            master = tk.Menu(master,tearoff=0)
            if True:
                master.add_command(label='Info')
        master.master.add_cascade(label='Hilfe',menu=master)
        master = master.master
    master = master.master
    master.mainloop()
 
if __name__ == '__main__':
    main()
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: :lol: selten so gelacht. Aber ich befürchte, Du meinst das ernst.

Wenn eine Funktion mehr als eine Handvoll Zeilen hat, sollte man sie in mehrere sinnvolle Funktionen aufteilen und nicht irgendwelche Kosmetik mit sinnfreien if-Blöcken machen.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben:@Alfons Mittelmeyer: :lol: selten so gelacht. Aber ich befürchte, Du meinst das ernst.

Wenn eine Funktion mehr als eine Handvoll Zeilen hat, sollte man sie in mehrere sinnvolle Funktionen aufteilen und nicht irgendwelche Kosmetik mit sinnfreien if-Blöcken machen.
Das ist Sourcecode im XML Stil. XML teilt man auch nicht in Funktionen auf und beschwert sich auch nicht darüber, dass es dort nicht so ist.
BlackJack

@Alfons Mittelmeyer: XML kennt keine Funktionen, und es gibt viele die sich über die nicht-lesbarkeit von XML beschweren. Das wurde in erster Linie dazu erfunden um *maschinenlesbar* zu sein. Manche XML-Formate sind auch für Menschen lesbar, aber bei weitem nicht alle. Und die Formate die für Menschen lesbar sein müssen, bieten tatsächlich oft Möglichkeiten um das Dokument in kleineren Abschnitten mit Namen zu organisieren, also so etwas ähnliches wie „auf Funktionen aufteilen“, damit man nicht alles in einem grossen, unübersichtlichen Klumpen schreiben und lesen muss.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben:@Alfons Mittelmeyer: :lol: selten so gelacht. Aber ich befürchte, Du meinst das ernst.

Wenn eine Funktion mehr als eine Handvoll Zeilen hat, sollte man sie in mehrere sinnvolle Funktionen aufteilen und nicht irgendwelche Kosmetik mit sinnfreien if-Blöcken machen.
Das mit den Funktionen kann man machen. Aber der Code wird dann länger und man kann leicht den Überblick verlieren. Das folgende geht ja noch. Aber man könnte ja auch die Funktionen in beliebiger Reihenfolge in den Source Code schreiben. Dann würde sich wohl so schnell keiner mehr auskennen, besonders nicht wenn man dann auch noch irgendwelche nichtssagenden Namen vergeben würde.

Wenn man keine guten Namen wählt, ist mit dem Durchblick ziemlich Ende. Das wäre mit Funktionen:

Code: Alles auswählen

import tkinter as tk
 
from functools import partial
 
# so etwas würde man importieren =================
class EventBroker():
    def __init__(self):
        self._dictionary_ = {}
 
    def subscribe(self,message_id,callback):
        self._dictionary_[message_id] = callback
 
    def publish(self,message_id,*args,**kwargs):
        self._dictionary_[message_id](*args,**kwargs)
 
eventbroker = EventBroker()
publish = eventbroker.publish
subscribe = eventbroker.subscribe
# ==============================================

def zeile_01(master):
    master = tk.Frame(master)
    return master

def zeile_02(master):
    master.pack(fill='both', expand=1)
    return master

def zeile_03(master):
    master.rowconfigure(0,weight=1)
    return master

def zeile_04(master):
    master.columnconfigure(0,weight=1)
    return master

def zeile_05(master):
    frames = {}
    return master,frames

def zeile_06(master,frames):
    subscribe('SHOW_FRAME',lambda frame_id, frames=frames: frames[frame_id].lift())
    return master

def zeile_07(master,frames):
    master = tk.Frame(master)
    return master

def zeile_08(master,frames):
    frames['Benutzereinstellungen'] = master
    return master

def zeile_09(master,frames):
    master.grid(sticky='nesw', row=0)
    return master

def zeile_10(master,frames):
    tk.Label(master,font = 'Verdana 12', text='Page One!!!').pack(padx=10, pady=20)
    return master

def zeile_11(master,frames):
    tk.Button(master,text = 'Back to Home',command=partial(publish,'SHOW_FRAME','RemoteManager')).pack()
    return master

def zeile_12(master,frames):
    tk.Button(master,text = 'Page Two',command=partial(publish,'SHOW_FRAME','PageTwo')).pack()
    return master

def zeile_13(master,frames):
    master = tk.Frame(master.master)
    return master

def zeile_14(master,frames):
    frames['PageTwo'] = master
    return master

def zeile_15(master,frames):
    master.grid(sticky='nesw', row=0)
    return master

def zeile_16(master,frames):
    tk.Label(master,font = 'Verdana 12', text='Page Two!!!').pack(padx=10, pady=10)
    return master

def zeile_17(master,frames):
    tk.Button(master,text = 'Back to Home',command=partial(publish,'SHOW_FRAME','RemoteManager')).pack()
    return master

def zeile_18(master,frames):
    tk.Button(master,text = 'Page One',command=partial(publish,'SHOW_FRAME','Benutzereinstellungen')).pack()
    return master

def zeile_19(master,frames):
    master = tk.Frame(master.master)
    return master

def zeile_20(master,frames):
    frames['RemoteManager'] = master
    return master

def zeile_21(master,frames):
    master.grid(sticky='nesw', row=0)
    return master

def zeile_22(master,frames):
    tk.Label(master,text = 'Willkommen im Remote Manager').pack(padx=25, pady=15)
    return master

def zeile_23(master,frames):
    tk.Button(master,text = 'Benutzereinstellungen', width = 18,command=partial(publish,'SHOW_FRAME','Benutzereinstellungen')).pack()
    return master

def zeile_24(master,frames):
    tk.Label(master).pack(padx=25, pady=1)
    return master

def zeile_25(master,frames):
    tk.Button(master,text ='Bildschirmeinstellungen', width = 18).pack()
    return master

def zeile_26(master,frames):
    tk.Label(master).pack(padx=25, pady=1)
    return master

def zeile_27(master,frames):
    tk.Button(master,text = 'Servereinstellungen', width = 18,command=partial(publish,'SHOW_FRAME','PageTwo')).pack()
    return master

def zeile_28(master,frames):
    tk.Label(master).pack(padx=25, pady=1)
    return master

def zeile_29(master,frames):
    frames['RemoteManager'].lift()
    return master

def zeile_30(master):
    master = tk.Menu(master.master.master)
    return master

def zeile_31(master):
    master.master['menu'] = master
    return master

def zeile_32(master):
    master = tk.Menu(master,tearoff=0)
    return master

def zeile_33(master):
    master.add_command(label='Komplettes Setup',command=partial(publish,'SHOW_FRAME','RemoteManager'))
    return master

def zeile_34(master):
    master.add_separator()
    return master

def zeile_35(master):
    master.add_command(label='Benutzereinstellungen',command=partial(publish,'SHOW_FRAME','Benutzereinstellungen'))
    return master

def zeile_36(master):
    master.add_command(label='Bildschirmeinstellungen')
    return master

def zeile_37(master):
    master.add_command(label='Servereinstellungen',command=partial(publish,'SHOW_FRAME','PageTwo'))
    return master

def zeile_38(master):
    master.add_separator()
    return master

def zeile_39(master):
    master.add_command(label ='Beenden')
    return master

def zeile_40(master):
    master.master.add_cascade(label='Manager',menu=master)
    return master

def zeile_41(master):
    master = tk.Menu(master.master,tearoff=0)
    return master

def zeile_42(master):
    master.add_command(label='Info')
    return master

def zeile_43(master):
    master.master.add_cascade(label='Hilfe',menu=master)
    return master

def zeile_44(master):
    master = master.master.master
    return master

def zeile_45(master):
    master.mainloop()
    return master


def zeile_01_04(master):
    master = zeile_01(master)
    master = zeile_02(master)
    master = zeile_03(master)
    master = zeile_04(master)
    return master

def zeile_05_12(master):
    master,frames = zeile_05(master)
    master = zeile_06(master,frames)
    master = zeile_07(master,frames)
    master = zeile_08(master,frames)
    master = zeile_09(master,frames)
    master = zeile_10(master,frames)
    master = zeile_11(master,frames)
    master = zeile_12(master,frames)
    return master,frames

def zeile_13_18(master,frames):
    master = zeile_13(master,frames)
    master = zeile_14(master,frames)
    master = zeile_15(master,frames)
    master = zeile_16(master,frames)
    master = zeile_17(master,frames)
    master = zeile_18(master,frames)
    return master

def zeile_19_29(master,frames):
    master = zeile_19(master,frames)
    master = zeile_20(master,frames)
    master = zeile_21(master,frames)
    master = zeile_22(master,frames)
    master = zeile_23(master,frames)
    master = zeile_24(master,frames)
    master = zeile_25(master,frames)
    master = zeile_26(master,frames)
    master = zeile_27(master,frames)
    master = zeile_28(master,frames)
    master = zeile_29(master,frames)
    return master

def zeile_30_39(master):
    master = zeile_30(master)
    master = zeile_31(master)
    master = zeile_32(master)
    master = zeile_33(master)
    master = zeile_34(master)
    master = zeile_35(master)
    master = zeile_36(master)
    master = zeile_37(master)
    master = zeile_38(master)
    master = zeile_39(master)
    return master
 
def zeile_40_45(master):
    master = zeile_40(master)
    master = zeile_41(master)
    master = zeile_42(master)
    master = zeile_43(master)
    master = zeile_44(master)
    master = zeile_45(master)
    return master

def zeile_01_45(master):
    master = zeile_01_04(master)
    master,frames = zeile_05_12(master)
    master = zeile_13_18(master,frames)
    master = zeile_19_29(master,frames)
    master = zeile_30_39(master)
    master = zeile_40_45(master)


if __name__ == '__main__':
    zeile_01_45(tk.Tk())
Und außerdem wäre es eine Sysiphus Arbeit, sich für die Funktionen sinnvolle Namen auszudenken. Die Hauptzeit des Programmierens besteht also darin, sich Namen auszudenken. Diese Zeit könnte man doch auch sinnvoller nutzen. Und dann passiert es auch, dass man sich nach einiger Zeit nicht mehr an die Namen erinnert und dann die Source Codes danach durchwühlen muß.
Zuletzt geändert von Alfons Mittelmeyer am Montag 21. August 2017, 10:54, insgesamt 1-mal geändert.
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Was ist denn das fuer ein Unsinn? Natuerlich gewinnt der Code nichts, wenn du ohne Sinn & Verstand einfach Code-Zeilen in durchnummerierte Funktionen verfrachtest, und die dann aufrufst. Aber das ist nicht was Sirius3 oder irgendwer hier gemeint hat.

Eine sinnvolle Aufteilung waere in Funktionen, die jeweils

- einen Screen laden (aus einer UI-Datei)
- daraus PER NAMEN die Widgets holen, die sie brauchen, womit Layout und Logik entkoppelt sind.
- die gewuenschten Aktionen an die Widgets binden.

Womit du auf Funktionen wie setup_main_screen, setup_network_settings, setup_user_settings etc kommst.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

__deets__ hat geschrieben:Was ist denn das fuer ein Unsinn? Natuerlich gewinnt der Code nichts, wenn du ohne Sinn & Verstand einfach Code-Zeilen in durchnummerierte Funktionen verfrachtest, und die dann aufrufst. Aber das ist nicht was Sirius3 oder irgendwer hier gemeint hat.

Eine sinnvolle Aufteilung waere in Funktionen, die jeweils

- einen Screen laden (aus einer UI-Datei)
- daraus PER NAMEN die Widgets holen, die sie brauchen, womit Layout und Logik entkoppelt sind.
- die gewuenschten Aktionen an die Widgets binden.

Womit du auf Funktionen wie setup_main_screen, setup_network_settings, setup_user_settings etc kommst.
Dann war mein Code doch gar nicht verkehrt. Nur hatte ich da bereits die Logik drin. Die habe ich jetzt rausgemacht:

screen.py

Code: Alles auswählen

import tkinter as tk

def screen(master):
    master = tk.Frame(master)
    master.pack(fill='both', expand=1)
    master.rowconfigure(0,weight=1)
    master.columnconfigure(0,weight=1)
    master = tk.Frame(master,name='page_one')
    master.grid(sticky='nesw', row=0)
    tk.Label(master,font = 'Verdana 12', text='Page One!!!').pack(padx=10, pady=20)
    tk.Button(master,text = 'Back to Home').pack()
    tk.Button(master,text = 'Page Two').pack()
    master = tk.Frame(master.master,name='page_two')
    master.grid(sticky='nesw', row=0)
    tk.Label(master,font = 'Verdana 12', text='Page Two!!!').pack(padx=10, pady=10)
    tk.Button(master,text = 'Back to Home').pack()
    tk.Button(master,text = 'Page One').pack()
    master = tk.Frame(master.master,name='remote_manager')
    master.grid(sticky='nesw', row=0)
    tk.Label(master,text = 'Willkommen im Remote Manager').pack(padx=25, pady=15)
    tk.Button(master,text = 'Benutzereinstellungen', width = 18).pack()
    tk.Label(master).pack(padx=25, pady=1)
    tk.Button(master,text ='Bildschirmeinstellungen', width = 18).pack()
    tk.Label(master).pack(padx=25, pady=1)
    tk.Button(master,text = 'Servereinstellungen', width = 18).pack()
    tk.Label(master).pack(padx=25, pady=1)
    master = tk.Menu(master.master.master)
    master.master['menu'] = master
    master = tk.Menu(master,name = 'manager_menu',tearoff=0)
    master.items = { 'remote_manager_index' : 0,'page_one_index' : 2, 'page_two_index' : 4, 'beenden_index' : 6 }
    master.add_command(label='Komplettes Setup')
    master.add_separator()
    master.add_command(label='Benutzereinstellungen')
    master.add_command(label='Bildschirmeinstellungen')
    master.add_command(label='Servereinstellungen')
    master.add_separator()
    master.add_command(label ='Beenden')
    master.master.add_cascade(label='Manager',menu=master)
    master = tk.Menu(master.master,name = 'hilfe_menu',tearoff=0)
    master.items = { 'info_index' : 0 }
    master.add_command(label='Info')
    master.master.add_cascade(label='Hilfe',menu=master)
    master = master.master.master
    return master
 
if __name__ == '__main__':
    screen(tk.Tk()).mainloop()
Und natürlich ist das sinnvoller Code. Das ist nämlich das UI File, bzw. Code wie er ausgeführt würde, wenn man ein anderes UI File Format lädt.

Und dann kann man den screen laden und könnte danach die logik reinmachen.

Da ist die Logik noch nicht drin, aber das kann man dann tun:

Code: Alles auswählen

import tkinter as tk
import screen

root = tk.Tk()
screen.screen(root) # screen laden

# eigener code für die Logik

root.mainloop()
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Es bleibt immer noch die Frage: Klassen, Attribute, Methoden wofür braucht man das?

Das ist der sogenannte GUI File - da hatten noch Namen gefehlt:

Code: Alles auswählen

import tkinter as tk

def screen(master):
    master = tk.Frame(master)
    master.pack(fill='both', expand=1)
    master.rowconfigure(0,weight=1)
    master.columnconfigure(0,weight=1)
    master = tk.Frame(master,name='page_one')
    master.grid(sticky='nesw', row=0)
    tk.Label(master,font = 'Verdana 12', text='Page One!!!').pack(padx=10, pady=20)
    tk.Button(master,name='page_one_button_for_remote_manager',text = 'Back to Home').pack()
    tk.Button(master,name='page_one_button_for_page_two',text = 'Page Two').pack()
    master = tk.Frame(master.master,name='page_two')
    master.grid(sticky='nesw', row=0)
    tk.Label(master,font = 'Verdana 12', text='Page Two!!!').pack(padx=10, pady=10)
    tk.Button(master,name='page_two_button_for_remote_manager',text = 'Back to Home').pack()
    tk.Button(master,name='page_two_button_for_page_one',text = 'Page One').pack()
    master = tk.Frame(master.master,name='remote_manager')
    master.grid(sticky='nesw', row=0)
    tk.Label(master,text = 'Willkommen im Remote Manager').pack(padx=25, pady=15)
    tk.Button(master,name='remote_manager_button_for_page_one',text = 'Benutzereinstellungen', width = 18).pack()
    tk.Label(master).pack(padx=25, pady=1)
    tk.Button(master,text ='Bildschirmeinstellungen', width = 18).pack()
    tk.Label(master).pack(padx=25, pady=1)
    tk.Button(master,name='remote_manager_button_for_page_two',text = 'Servereinstellungen', width = 18).pack()
    tk.Label(master).pack(padx=25, pady=1)
    master = tk.Menu(master.master.master)
    master.master['menu'] = master
    master = tk.Menu(master,name = 'manager_menu',tearoff=0)
    master.items = { 'remote_manager_index' : 0,'page_one_index' : 2, 'page_two_index' : 4, 'beenden_index' : 6 }
    master.add_command(label='Komplettes Setup')
    master.add_separator()
    master.add_command(label='Benutzereinstellungen')
    master.add_command(label='Bildschirmeinstellungen')
    master.add_command(label='Servereinstellungen')
    master.add_separator()
    master.add_command(label ='Beenden')
    master.master.add_cascade(label='Manager',menu=master)
    master = tk.Menu(master.master,name = 'hilfe_menu',tearoff=0)
    master.items = { 'info_index' : 0 }
    master.add_command(label='Info')
    master.master.add_cascade(label='Hilfe',menu=master)
    master = master.master.master
    return master
 
if __name__ == '__main__':
    screen(tk.Tk()).mainloop()
Das ist das Start Script mit der Logik:

Code: Alles auswählen

import tkinter as tk
import screen
import builder
from functools import partial

def main():

    root = tk.Tk()
    screen.screen(root) # screen laden

    widget = builder.Builder(root).get_object

    frames = {
        'remote_manager' : widget('remote_manager'),
        'page_one' : widget('page_one'),
        'page_two' : widget('page_two'),
    }

    def show_frame(frame_id):
        frames[frame_id].lift()

    remote_manager = partial(show_frame,'remote_manager')
    page_one = partial(show_frame,'page_one')
    page_two = partial(show_frame,'page_two')

    manager_menu = widget('manager_menu')
    manager_menu.entryconfig(manager_menu.items['remote_manager_index'],command=remote_manager)
    manager_menu.entryconfig(manager_menu.items['page_one_index'],command=page_one)
    manager_menu.entryconfig(manager_menu.items['page_two_index'],command=page_two)

    widget('remote_manager_button_for_page_one')['command'] = page_one
    widget('remote_manager_button_for_page_two')['command'] = page_two
    widget('page_one_button_for_remote_manager')['command'] = remote_manager
    widget('page_one_button_for_page_two')['command'] = page_two
    widget('page_two_button_for_remote_manager')['command'] = remote_manager
    widget('page_two_button_for_page_one')['command'] = page_one

    root.mainloop()

if __name__ == '__main__':
    main()
Und das ist builder.py:

Code: Alles auswählen

import re

class Builder:
    def __init__(self,root):
        self.name_dict = {}
        self.build_names(root,self.name_dict)

    def get_object(self,id):
        return self.name_dict[id]

    def build_names(self,container,name_dict):
        for child in container.winfo_children():
            name = str(child).split('.')[-1]
            if name[0] == '#': # for exported GuiDesigner Sources (with names)
                name = re.split('[#]\d+[_]',name)[-1]
            name_dict[name] = child
            self.build_names(child,name_dict)
Resultat: den GUI Code kann man schreiben, wie man will, Hauptsache es sind Namen drin

Und anscheinend kann man den Logik Code mit den Bindings auch so schreiben, wie es einem in den Sinn kommt, wenn man die Namen hat. Das halte ich aber für komplexe GUIs nicht empfehlenswert.
BlackJack

@Alfons Mittelmeyer: Das ist alles GUI-Code ohne Programmlogik.
Benutzeravatar
noisefloor
User
Beiträge: 3829
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

Es bleibt immer noch die Frage: Klassen, Attribute, Methoden wofür braucht man das?
Genau. Endlich erkennt mal jemand diesen katastrophlen Design-Fehler. Pro-Tipp: wechsel doch von Python auf Go, Go kennt keine Klassen. Da stellen sich so fragen gar nicht. Plus du hast eine Sprache, die modern und hip ist. Als Service für dich: Link zum Go-Forum.

Gruß, noisefloor
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

noisefloor hat geschrieben: Pro-Tipp: wechsel doch von Python auf Go, Go kennt keine Klassen. Da stellen sich so fragen gar nicht. Plus du hast eine Sprache, die modern und hip ist. Als Service für dich: Link zum Go-Forum.
Gruß, noisefloor
Weiß nicht, was daran so modern sein sollte. C gibt es schon lange als Compiler. Mit Go gibt es das oder so ähnlich eben auch als Interpreter.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

noisefloor hat geschrieben:Hallo,
Es bleibt immer noch die Frage: Klassen, Attribute, Methoden wofür braucht man das?
Genau. Endlich erkennt mal jemand diesen katastrophlen Design-Fehler.
...
Gruß, noisefloor
Ich schreib ja nicht, dass man sie nicht braucht. Da Frage war doch, wofür man sie braucht.
Ist eigentlich einfach. Widget IDs sind für komplexe GUI Programme nicht zu empfehlen. Sollte man sich erst gar nicht angewöhnen, Für große Programme empfiehlt sich die Unterteilung in Module. Bei kleineren Programmen aber hätte man gerne alles zusammen in einem File. Und daher verwendet man Klassen, denn:

durch eine Klasse und dem Aufruf einer Methode für ein Objekt kann man einen Funktionsaufruf in einem Modul simulieren.
Antworten