Na im Prinzip hast du es ja schon verstanden.
Nun zu Deinen Fragen.
Code: Alles auswählen
class MyGUI(object):
def __init__(self, handlers):
self.handlers = handlers
self._buildgui()
__init__ wird immer aufgerufen, wenn eine neue Instanz (ein neues Objekt) der Klasse erzeugt wird, beim Instanziieren - im Hauptmodul
myGUI = MyGUI(handler_dict) - können an die Klasse so auch Parameter/Objekte mitübergeben werden.
Im konkreten Fall wird ein Dictionary mit den Funktionen die bei einer Aktion in der GUI ausgeführt werden sollen mitübergeben und dieses Dictionary in der Instanz als Attribut handlers gespeichert. Dies geschieht bei self.handlers = handlers. Dabei müssen das Attribut und der Parameter aber nicht den gleichen namen haben. es könnte auch heissen self.buttonhandlers = handlers, wobei dann später beim Aufbau der gui auch self.handlers durch self.buttonhandlers ersetzt werden muss.
Code: Alles auswählen
self.button1 = Button(self.root, text=" 1 ", command=self.handlers.get("handle_button1",noop))
hmm das ist eine Eigenheit von mir, ich hätte es auch als
Code: Alles auswählen
self.button1 = Button(self.root, text=" 1 ", command=self.handlers["handle_button1"]
schreiben können, dann wärs gleich klarer, daß hier ein Eintrag vom Dictionary mit den Buttonhandlern, als command an den Button gebunden wird.
get(key, default) ist eine Methode von Dictionary, so wird, falls zu einem Button, oder anderen Widget, kein Eintrag im Dictionary steht, einen Dummyhandler bzw einen Universalhandler für den Button eingetragen. So kann ich in der Entwicklungsphase schon Buttons und andere Widgets einbauen, für die ich im Hauptmodul noch keine Funktion bereitgestellt habe.
Code: Alles auswählen
def do_button1():
myGUI.statusvar.set("Button 1 angeklickt")
statusvar ist ein Objekt vom Type StringVar aus Tkinter. Diese VariablenObjekte sind ein schönes Werkzeug für die Kommunikation der GUI mit dem eigentlichen Programm, da sie an ein oder mehrere Widgets, auch z.B. an ein Entrywidget gebunden werden können, und dann bei Eingabe eines neuen Wertes ins Widget, durch den User, auch ihren Wert ändern und wenn der Wert des Variablenobjekts durch das Programm, wie in meinem Beispiel, geändert wird, diese Änderung sofort im damit verbundenem Widget angezeigt wird. Hier zeigt sich auch die Mächtigkeit von OOP, Du brauchst gar nicht zu wissen, wie und wo der Inhalt des Variablenobjekts in der GUI dargestellt wird, das weiss das Variablenobjekt selber und erledigt automatisch, wenn mit der Methode
set(neuerWert) dem Objekt ein neuer Wert zugewiesen wird, alles weitere.
self.statusvar = StringVar(self.root) wird nur beim Initialisieren der GUI ausgeführt und wiest statusvar ein Objekt vom Type StringVar aus Tkinter zu. Danach wird nur noch der Inhalt des Objekts mit der Methode
set(neuerWert ) vom Programm aus ein neuer Inhalt gebeben.
Code: Alles auswählen
handler_dict = {
"handle_button1" : do_button1,
"handle_button2" : do_button2
}
ist einfach nur ein Dictionary mit den Keys "handle_button1" und "handle_button2" und den zugehörigen daten "do_button1" und "do_button2". Da auch Funktionen Objekte sind, könne diese an Variablen zugewiesen oder in Listen oder Dictionarys gespeichert werden.
Das was im Hauptteil handler_dict heisst landet irgendwie in der Klasse als self.handlers. self.handlers.get("handle_button1",noop) liest aus diesem handlers die entsprechende anweisung (do_button1) aus. Ich verstehe aber trotzdem immer noch nicht wie es dann zum Aufruf der eigentlichen Funktion kommt. Wieso kann ich dann beim command nicht gleich do_button1 schreiben, wenn das doch an sich der selbe Wert ist.
Du kannst beim command eben nicht gleich do_button1 schreiben, weil diese Funktion weder in der Klasse noch im Modul sichtbar ist. Wenn Du nur ein Modul hättest ginge es auch so. Zum Aufruf der Funktion aus dem Hauptmodul kommt es, da hier mit Objekten, genauer mit Verweisen auf Objekte gearbeitet wird. bei __init__(self, handlers) wird nicht das Dictionary an MyGUI übergeben, sondern nur ein Verweis, der auf das Dictionary das im Hauptmodul definiert wurde. Genauso verhält es sich dann mit der Anweisung
command = self.handlers.get("handle_button1", noop) hier wird ein Verweis aus dem Dictionary geholt und an den Button gebunden, falls kein passender Eintrag im Dictionary enthalten ist, wird ein Verweis auf noop an den Button gebunden.
Ich verwende hier den Ausdruck Verweis anstelle von Pointer, da Python, zum Glück, keine Pointerarithmetik kennt. Falls Du Erfahrung mit C++ oder Java hast, kannst du statt Verweis auch Pointer sagen, allerdings mit der eben genannten Einschränkung.
Gruß
Dookie