Warum Klassen verwenden, wenn eine Tkinter-GUI in Python programmiert wird?

19

Ich programmiere hauptsächlich in Python und habe ein paar GUIs mit Tkinter programmiert. Jedes Tutorial, das ich je gesehen habe, hat empfohlen, eine Klasse für die GUI zu definieren und zu verwenden, aber meine GUI läuft einwandfrei und verwendet nur Prozeduren ohne Klasse.

Warum eine Klasse benutzen? Aus meiner Sicht scheint es einfach eine zusätzliche Schicht von Komplexität und unnötigem Code zu sein.

Devon Muraoka
quelle

Antworten:

19

Warum eine Klasse benutzen? Weil es die Arbeit erleichtert, vorausgesetzt, Sie wissen, wie man objektorientierte Programmierung macht, und vorausgesetzt, Sie schreiben eine nicht triviale GUI. Mithilfe von Objekten können Sie Ihren Code auf einfache Weise in eigenständige modulare Einheiten unterteilen, und die Modularisierung Ihres Codes wird im Allgemeinen als bewährte Methode angesehen.

GUI-Programmierung eignet sich leicht für einen objektorientierten Stil, da eine GUI nur aus Objekten besteht - Beschriftungen, Schaltflächen, Bildlaufleisten, Textbereichen usw. Da Sie bereits Objekte verwenden, ist es sinnvoll, Ihren Code in größere Objekte zu organisieren . Die Symbolleiste ist ein Objekt, die Statusleiste ist ein Objekt, der Navigationsbereich ist ein Objekt, der Hauptbereich ist ein Objekt, jede Notizbuchregisterkarte ist ein Objekt und so weiter.

Selbst wenn Ihr Code nicht sehr komplex ist, können Sie aus praktischer Sicht Bindungen und Rückrufe früher in der Datei definieren als die Definition der Funktion, die Sie aufrufen, was meiner Meinung nach sehr sinnvoll ist.

Stellen Sie sich zum Beispiel ein einfaches Beispiel vor (vorausgesetzt, dass tkinter wie import tkinter as tk(python3) oder import Tkinter as tk(python2) importiert wurde):

def quit(event=None):
    sys.exit()
root = tk.Tk()
label = tk.Label(root, text="Hello, world")
label.pack()
label.bind("<1>", quit)
root.mainloop()

Für mich ist der Ablauf dieses Codes völlig falsch. Ich muss die quit-Methode definieren, bevor ich darauf verweise, und die Erstellung des Root-Fensters und der Aufruf von mainloop werden durch den gesamten anderen Code getrennt.

Mit Klassen kann ich den Code jedoch in einer natürlicheren Reihenfolge schreiben:

class MyWindow(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="Hello, world")
        label.pack()
        label.bind("<1>", self.quit)
    def quit(self, event=None):
        sys.exit()

root = tk.Tk()
MyWindow(root).pack()
root.mainloop()

Der Hauptteil der Benutzeroberfläche befindet sich ganz oben in der Datei, und unterstützender Code befindet sich darunter. Jetzt können Sie natürlich Funktionen verwenden, um fast das Gleiche zu erreichen. Meiner Meinung nach macht der Unterricht alles nur ein bisschen einfacher.

Ein weiterer Vorteil ist, dass ich das enthaltende Fenster jetzt einfach ändern kann, ohne etwas am "Haupt" -Fenster ändern zu müssen (und umgekehrt). Das heißt, ich kann der Haupt-GUI Rahmen oder einen vollständigen neuen Abschnitt hinzufügen, muss jedoch keine einzige Codezeile in MyWindow berühren. Vergleichen Sie dies mit dem Prozedurcode, in dem Sie möglicherweise die label.pack()Anweisung ändern müssen , und den Anweisungen pack (oder grid) aller anderen Widgets in der Benutzeroberfläche.

Alles, was gesagt wird, ist jedoch nicht notwendig, einen objektorientierten Ansatz zu verwenden, um guten, sauberen und wartbaren Code zu schreiben. Es kann sein, aber es kann auch zu schlechtem Code führen. Letztendlich ist ein objektorientierter Ansatz nur ein Werkzeug. Ob Sie es verwenden oder nicht, und ob Sie es richtig verwenden oder nicht, hängt von vielen Faktoren ab. Es kann also durchaus sein, dass für Sie und für den von Ihnen geschriebenen Code ein funktionaler Stil durchaus akzeptabel ist. Ich glaube, Sie werden feststellen, dass ein objektorientierter Ansatz mit zunehmender Komplexität Ihrer Programme die Organisation und Pflege Ihres Codes erleichtert.

Bryan Oakley
quelle
Warum haben Sie im zweiten Beispiel einen Frame verwendet? Konnten Sie es nicht vermeiden, wie Sie es im ersten Beispiel getan haben? Gibt es ein Geheimnis für die Verwendung von Frame mit Klassen?
Multigoodverse
2
Der Rahmen ist einfach für die Bequemlichkeit. Es ist kein Geheimnis, von Frame zu erben. Ich hätte von objectjeder anderen Klasse erben können, aber normalerweise erstelle ich trotzdem einen Frame. Wenn ich alles in einen Frame setze, ist es sinnvoll, die Klasse als Frame zu definieren. .
Bryan Oakley
1
Sinnvoll, danke! Ich habe auch gesehen, dass andere self vor Variablen verwenden, aber ich sehe, dass Sie so etwas wie label=tk.Label()anstelle von verwenden self.tk.Label(). Ist das eine Stilwahl? Hier ist ein Beispiel mit self: python-textbok.readthedocs.org/en/1.0/…
multigoodverse
1
@BryanOakley, ich denke, Sie wollten in der folgenden Zeile von MyWindow .__ init__ Parent anstelle von Root verwenden: "label = tk.Label (root, text =" Hello, world ")"
user3885927
1
@ user3885927: ja! Wow, es hat fast drei Jahre gedauert, bis jemand das bemerkt hat. Allerdings nicht, parentsondern vielmehr self, da die Klasse selbst ein Frame ist. Vielen Dank!
Bryan Oakley